OSDN Git Service

Thanos did someting
[bytom/vapor.git] / vendor / github.com / fsnotify / fsnotify / windows.go
diff --git a/vendor/github.com/fsnotify/fsnotify/windows.go b/vendor/github.com/fsnotify/fsnotify/windows.go
deleted file mode 100644 (file)
index 09436f3..0000000
+++ /dev/null
@@ -1,561 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build windows
-
-package fsnotify
-
-import (
-       "errors"
-       "fmt"
-       "os"
-       "path/filepath"
-       "runtime"
-       "sync"
-       "syscall"
-       "unsafe"
-)
-
-// Watcher watches a set of files, delivering events to a channel.
-type Watcher struct {
-       Events   chan Event
-       Errors   chan error
-       isClosed bool           // Set to true when Close() is first called
-       mu       sync.Mutex     // Map access
-       port     syscall.Handle // Handle to completion port
-       watches  watchMap       // Map of watches (key: i-number)
-       input    chan *input    // Inputs to the reader are sent on this channel
-       quit     chan chan<- error
-}
-
-// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
-func NewWatcher() (*Watcher, error) {
-       port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0)
-       if e != nil {
-               return nil, os.NewSyscallError("CreateIoCompletionPort", e)
-       }
-       w := &Watcher{
-               port:    port,
-               watches: make(watchMap),
-               input:   make(chan *input, 1),
-               Events:  make(chan Event, 50),
-               Errors:  make(chan error),
-               quit:    make(chan chan<- error, 1),
-       }
-       go w.readEvents()
-       return w, nil
-}
-
-// Close removes all watches and closes the events channel.
-func (w *Watcher) Close() error {
-       if w.isClosed {
-               return nil
-       }
-       w.isClosed = true
-
-       // Send "quit" message to the reader goroutine
-       ch := make(chan error)
-       w.quit <- ch
-       if err := w.wakeupReader(); err != nil {
-               return err
-       }
-       return <-ch
-}
-
-// Add starts watching the named file or directory (non-recursively).
-func (w *Watcher) Add(name string) error {
-       if w.isClosed {
-               return errors.New("watcher already closed")
-       }
-       in := &input{
-               op:    opAddWatch,
-               path:  filepath.Clean(name),
-               flags: sysFSALLEVENTS,
-               reply: make(chan error),
-       }
-       w.input <- in
-       if err := w.wakeupReader(); err != nil {
-               return err
-       }
-       return <-in.reply
-}
-
-// Remove stops watching the the named file or directory (non-recursively).
-func (w *Watcher) Remove(name string) error {
-       in := &input{
-               op:    opRemoveWatch,
-               path:  filepath.Clean(name),
-               reply: make(chan error),
-       }
-       w.input <- in
-       if err := w.wakeupReader(); err != nil {
-               return err
-       }
-       return <-in.reply
-}
-
-const (
-       // Options for AddWatch
-       sysFSONESHOT = 0x80000000
-       sysFSONLYDIR = 0x1000000
-
-       // Events
-       sysFSACCESS     = 0x1
-       sysFSALLEVENTS  = 0xfff
-       sysFSATTRIB     = 0x4
-       sysFSCLOSE      = 0x18
-       sysFSCREATE     = 0x100
-       sysFSDELETE     = 0x200
-       sysFSDELETESELF = 0x400
-       sysFSMODIFY     = 0x2
-       sysFSMOVE       = 0xc0
-       sysFSMOVEDFROM  = 0x40
-       sysFSMOVEDTO    = 0x80
-       sysFSMOVESELF   = 0x800
-
-       // Special events
-       sysFSIGNORED   = 0x8000
-       sysFSQOVERFLOW = 0x4000
-)
-
-func newEvent(name string, mask uint32) Event {
-       e := Event{Name: name}
-       if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO {
-               e.Op |= Create
-       }
-       if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF {
-               e.Op |= Remove
-       }
-       if mask&sysFSMODIFY == sysFSMODIFY {
-               e.Op |= Write
-       }
-       if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM {
-               e.Op |= Rename
-       }
-       if mask&sysFSATTRIB == sysFSATTRIB {
-               e.Op |= Chmod
-       }
-       return e
-}
-
-const (
-       opAddWatch = iota
-       opRemoveWatch
-)
-
-const (
-       provisional uint64 = 1 << (32 + iota)
-)
-
-type input struct {
-       op    int
-       path  string
-       flags uint32
-       reply chan error
-}
-
-type inode struct {
-       handle syscall.Handle
-       volume uint32
-       index  uint64
-}
-
-type watch struct {
-       ov     syscall.Overlapped
-       ino    *inode            // i-number
-       path   string            // Directory path
-       mask   uint64            // Directory itself is being watched with these notify flags
-       names  map[string]uint64 // Map of names being watched and their notify flags
-       rename string            // Remembers the old name while renaming a file
-       buf    [4096]byte
-}
-
-type indexMap map[uint64]*watch
-type watchMap map[uint32]indexMap
-
-func (w *Watcher) wakeupReader() error {
-       e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil)
-       if e != nil {
-               return os.NewSyscallError("PostQueuedCompletionStatus", e)
-       }
-       return nil
-}
-
-func getDir(pathname string) (dir string, err error) {
-       attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname))
-       if e != nil {
-               return "", os.NewSyscallError("GetFileAttributes", e)
-       }
-       if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
-               dir = pathname
-       } else {
-               dir, _ = filepath.Split(pathname)
-               dir = filepath.Clean(dir)
-       }
-       return
-}
-
-func getIno(path string) (ino *inode, err error) {
-       h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path),
-               syscall.FILE_LIST_DIRECTORY,
-               syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
-               nil, syscall.OPEN_EXISTING,
-               syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0)
-       if e != nil {
-               return nil, os.NewSyscallError("CreateFile", e)
-       }
-       var fi syscall.ByHandleFileInformation
-       if e = syscall.GetFileInformationByHandle(h, &fi); e != nil {
-               syscall.CloseHandle(h)
-               return nil, os.NewSyscallError("GetFileInformationByHandle", e)
-       }
-       ino = &inode{
-               handle: h,
-               volume: fi.VolumeSerialNumber,
-               index:  uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow),
-       }
-       return ino, nil
-}
-
-// Must run within the I/O thread.
-func (m watchMap) get(ino *inode) *watch {
-       if i := m[ino.volume]; i != nil {
-               return i[ino.index]
-       }
-       return nil
-}
-
-// Must run within the I/O thread.
-func (m watchMap) set(ino *inode, watch *watch) {
-       i := m[ino.volume]
-       if i == nil {
-               i = make(indexMap)
-               m[ino.volume] = i
-       }
-       i[ino.index] = watch
-}
-
-// Must run within the I/O thread.
-func (w *Watcher) addWatch(pathname string, flags uint64) error {
-       dir, err := getDir(pathname)
-       if err != nil {
-               return err
-       }
-       if flags&sysFSONLYDIR != 0 && pathname != dir {
-               return nil
-       }
-       ino, err := getIno(dir)
-       if err != nil {
-               return err
-       }
-       w.mu.Lock()
-       watchEntry := w.watches.get(ino)
-       w.mu.Unlock()
-       if watchEntry == nil {
-               if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil {
-                       syscall.CloseHandle(ino.handle)
-                       return os.NewSyscallError("CreateIoCompletionPort", e)
-               }
-               watchEntry = &watch{
-                       ino:   ino,
-                       path:  dir,
-                       names: make(map[string]uint64),
-               }
-               w.mu.Lock()
-               w.watches.set(ino, watchEntry)
-               w.mu.Unlock()
-               flags |= provisional
-       } else {
-               syscall.CloseHandle(ino.handle)
-       }
-       if pathname == dir {
-               watchEntry.mask |= flags
-       } else {
-               watchEntry.names[filepath.Base(pathname)] |= flags
-       }
-       if err = w.startRead(watchEntry); err != nil {
-               return err
-       }
-       if pathname == dir {
-               watchEntry.mask &= ^provisional
-       } else {
-               watchEntry.names[filepath.Base(pathname)] &= ^provisional
-       }
-       return nil
-}
-
-// Must run within the I/O thread.
-func (w *Watcher) remWatch(pathname string) error {
-       dir, err := getDir(pathname)
-       if err != nil {
-               return err
-       }
-       ino, err := getIno(dir)
-       if err != nil {
-               return err
-       }
-       w.mu.Lock()
-       watch := w.watches.get(ino)
-       w.mu.Unlock()
-       if watch == nil {
-               return fmt.Errorf("can't remove non-existent watch for: %s", pathname)
-       }
-       if pathname == dir {
-               w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
-               watch.mask = 0
-       } else {
-               name := filepath.Base(pathname)
-               w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED)
-               delete(watch.names, name)
-       }
-       return w.startRead(watch)
-}
-
-// Must run within the I/O thread.
-func (w *Watcher) deleteWatch(watch *watch) {
-       for name, mask := range watch.names {
-               if mask&provisional == 0 {
-                       w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED)
-               }
-               delete(watch.names, name)
-       }
-       if watch.mask != 0 {
-               if watch.mask&provisional == 0 {
-                       w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
-               }
-               watch.mask = 0
-       }
-}
-
-// Must run within the I/O thread.
-func (w *Watcher) startRead(watch *watch) error {
-       if e := syscall.CancelIo(watch.ino.handle); e != nil {
-               w.Errors <- os.NewSyscallError("CancelIo", e)
-               w.deleteWatch(watch)
-       }
-       mask := toWindowsFlags(watch.mask)
-       for _, m := range watch.names {
-               mask |= toWindowsFlags(m)
-       }
-       if mask == 0 {
-               if e := syscall.CloseHandle(watch.ino.handle); e != nil {
-                       w.Errors <- os.NewSyscallError("CloseHandle", e)
-               }
-               w.mu.Lock()
-               delete(w.watches[watch.ino.volume], watch.ino.index)
-               w.mu.Unlock()
-               return nil
-       }
-       e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0],
-               uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0)
-       if e != nil {
-               err := os.NewSyscallError("ReadDirectoryChanges", e)
-               if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
-                       // Watched directory was probably removed
-                       if w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) {
-                               if watch.mask&sysFSONESHOT != 0 {
-                                       watch.mask = 0
-                               }
-                       }
-                       err = nil
-               }
-               w.deleteWatch(watch)
-               w.startRead(watch)
-               return err
-       }
-       return nil
-}
-
-// readEvents reads from the I/O completion port, converts the
-// received events into Event objects and sends them via the Events channel.
-// Entry point to the I/O thread.
-func (w *Watcher) readEvents() {
-       var (
-               n, key uint32
-               ov     *syscall.Overlapped
-       )
-       runtime.LockOSThread()
-
-       for {
-               e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE)
-               watch := (*watch)(unsafe.Pointer(ov))
-
-               if watch == nil {
-                       select {
-                       case ch := <-w.quit:
-                               w.mu.Lock()
-                               var indexes []indexMap
-                               for _, index := range w.watches {
-                                       indexes = append(indexes, index)
-                               }
-                               w.mu.Unlock()
-                               for _, index := range indexes {
-                                       for _, watch := range index {
-                                               w.deleteWatch(watch)
-                                               w.startRead(watch)
-                                       }
-                               }
-                               var err error
-                               if e := syscall.CloseHandle(w.port); e != nil {
-                                       err = os.NewSyscallError("CloseHandle", e)
-                               }
-                               close(w.Events)
-                               close(w.Errors)
-                               ch <- err
-                               return
-                       case in := <-w.input:
-                               switch in.op {
-                               case opAddWatch:
-                                       in.reply <- w.addWatch(in.path, uint64(in.flags))
-                               case opRemoveWatch:
-                                       in.reply <- w.remWatch(in.path)
-                               }
-                       default:
-                       }
-                       continue
-               }
-
-               switch e {
-               case syscall.ERROR_MORE_DATA:
-                       if watch == nil {
-                               w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")
-                       } else {
-                               // The i/o succeeded but the buffer is full.
-                               // In theory we should be building up a full packet.
-                               // In practice we can get away with just carrying on.
-                               n = uint32(unsafe.Sizeof(watch.buf))
-                       }
-               case syscall.ERROR_ACCESS_DENIED:
-                       // Watched directory was probably removed
-                       w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
-                       w.deleteWatch(watch)
-                       w.startRead(watch)
-                       continue
-               case syscall.ERROR_OPERATION_ABORTED:
-                       // CancelIo was called on this handle
-                       continue
-               default:
-                       w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e)
-                       continue
-               case nil:
-               }
-
-               var offset uint32
-               for {
-                       if n == 0 {
-                               w.Events <- newEvent("", sysFSQOVERFLOW)
-                               w.Errors <- errors.New("short read in readEvents()")
-                               break
-                       }
-
-                       // Point "raw" to the event in the buffer
-                       raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
-                       buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName))
-                       name := syscall.UTF16ToString(buf[:raw.FileNameLength/2])
-                       fullname := filepath.Join(watch.path, name)
-
-                       var mask uint64
-                       switch raw.Action {
-                       case syscall.FILE_ACTION_REMOVED:
-                               mask = sysFSDELETESELF
-                       case syscall.FILE_ACTION_MODIFIED:
-                               mask = sysFSMODIFY
-                       case syscall.FILE_ACTION_RENAMED_OLD_NAME:
-                               watch.rename = name
-                       case syscall.FILE_ACTION_RENAMED_NEW_NAME:
-                               if watch.names[watch.rename] != 0 {
-                                       watch.names[name] |= watch.names[watch.rename]
-                                       delete(watch.names, watch.rename)
-                                       mask = sysFSMOVESELF
-                               }
-                       }
-
-                       sendNameEvent := func() {
-                               if w.sendEvent(fullname, watch.names[name]&mask) {
-                                       if watch.names[name]&sysFSONESHOT != 0 {
-                                               delete(watch.names, name)
-                                       }
-                               }
-                       }
-                       if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME {
-                               sendNameEvent()
-                       }
-                       if raw.Action == syscall.FILE_ACTION_REMOVED {
-                               w.sendEvent(fullname, watch.names[name]&sysFSIGNORED)
-                               delete(watch.names, name)
-                       }
-                       if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) {
-                               if watch.mask&sysFSONESHOT != 0 {
-                                       watch.mask = 0
-                               }
-                       }
-                       if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME {
-                               fullname = filepath.Join(watch.path, watch.rename)
-                               sendNameEvent()
-                       }
-
-                       // Move to the next event in the buffer
-                       if raw.NextEntryOffset == 0 {
-                               break
-                       }
-                       offset += raw.NextEntryOffset
-
-                       // Error!
-                       if offset >= n {
-                               w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.")
-                               break
-                       }
-               }
-
-               if err := w.startRead(watch); err != nil {
-                       w.Errors <- err
-               }
-       }
-}
-
-func (w *Watcher) sendEvent(name string, mask uint64) bool {
-       if mask == 0 {
-               return false
-       }
-       event := newEvent(name, uint32(mask))
-       select {
-       case ch := <-w.quit:
-               w.quit <- ch
-       case w.Events <- event:
-       }
-       return true
-}
-
-func toWindowsFlags(mask uint64) uint32 {
-       var m uint32
-       if mask&sysFSACCESS != 0 {
-               m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS
-       }
-       if mask&sysFSMODIFY != 0 {
-               m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE
-       }
-       if mask&sysFSATTRIB != 0 {
-               m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES
-       }
-       if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 {
-               m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME
-       }
-       return m
-}
-
-func toFSnotifyFlags(action uint32) uint64 {
-       switch action {
-       case syscall.FILE_ACTION_ADDED:
-               return sysFSCREATE
-       case syscall.FILE_ACTION_REMOVED:
-               return sysFSDELETE
-       case syscall.FILE_ACTION_MODIFIED:
-               return sysFSMODIFY
-       case syscall.FILE_ACTION_RENAMED_OLD_NAME:
-               return sysFSMOVEDFROM
-       case syscall.FILE_ACTION_RENAMED_NEW_NAME:
-               return sysFSMOVEDTO
-       }
-       return 0
-}