func TestNegativeTime(t *testing.T) {
	ts := NewTestCase(t)
	defer ts.Cleanup()

	_, err := os.Create(ts.origFile)
	if err != nil {
		t.Fatalf("Create failed: %v", err)
	}

	var stat syscall.Stat_t

	// set negative nanosecond will occur errors on UtimesNano as invalid argument
	ut := time.Date(1960, time.January, 10, 23, 0, 0, 0, time.UTC)
	tim := []syscall.Timespec{
		syscall.NsecToTimespec(ut.UnixNano()),
		syscall.NsecToTimespec(ut.UnixNano()),
	}
	err = syscall.UtimesNano(ts.mountFile, tim)
	if err != nil {
		t.Fatalf("UtimesNano failed: %v", err)
	}
	err = syscall.Lstat(ts.mountFile, &stat)
	if err != nil {
		t.Fatalf("Lstat failed: %v", err)
	}

	if stat.Atim.Sec >= 0 || stat.Mtim.Sec >= 0 {
		t.Errorf("Got wrong timestamps %v", stat)
	}
}
예제 #2
0
func setZeroModTime(filename string) error {
	var utimes = []syscall.Timespec{
		syscall.NsecToTimespec(0),
		syscall.NsecToTimespec(0),
	}

	return syscall.UtimesNano(filename, utimes)
}
예제 #3
0
파일: file_posix.go 프로젝트: ds2dev/gcc
// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
// The underlying filesystem may truncate or round the values to a
// less precise time unit.
// If there is an error, it will be of type *PathError.
func Chtimes(name string, atime time.Time, mtime time.Time) error {
	var utimes [2]syscall.Timespec
	utimes[0] = syscall.NsecToTimespec(atime.UnixNano())
	utimes[1] = syscall.NsecToTimespec(mtime.UnixNano())
	if e := syscall.UtimesNano(name, utimes[0:]); e != nil {
		return &PathError{"chtimes", name, e}
	}
	return nil
}
예제 #4
0
func UtimesNano(path string, atime time.Time, mtime time.Time) error {
	var utimes [2]syscall.Timespec
	utimes[0] = syscall.NsecToTimespec(atime.UnixNano())
	utimes[1] = syscall.NsecToTimespec(mtime.UnixNano())
	if err := syscall.UtimesNano(path, utimes[0:]); err != nil {
		return &os.PathError{"chtimes", path, err}
	}
	return nil
}
예제 #5
0
func UtimesNano(path string, atime time.Time, mtime time.Time) error {
	// Note that this is disambiguated from plain `os.Chtimes` only in that it refuses to fall back to lower precision on old kernels.
	// Like LUtimesNano, it depends on kernel 2.6.22 or newer.
	var utimes [2]syscall.Timespec
	utimes[0] = syscall.NsecToTimespec(atime.UnixNano())
	utimes[1] = syscall.NsecToTimespec(mtime.UnixNano())
	if err := syscall.UtimesNano(path, utimes[0:]); err != nil {
		return &os.PathError{"chtimes", path, err}
	}
	return nil
}
예제 #6
0
파일: fd_darwin.go 프로젝트: 8l/go-learn
func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
	var t *syscall.Timespec
	for len(p.events) == 0 {
		if nsec > 0 {
			if t == nil {
				t = new(syscall.Timespec)
			}
			*t = syscall.NsecToTimespec(nsec)
		}
		nn, e := syscall.Kevent(p.kq, nil, &p.eventbuf, t)
		if e != 0 {
			if e == syscall.EINTR {
				continue
			}
			return -1, 0, os.NewSyscallError("kevent", e)
		}
		if nn == 0 {
			return -1, 0, nil
		}
		p.events = p.eventbuf[0:nn]
	}
	ev := &p.events[0]
	p.events = p.events[1:len(p.events)]
	fd = int(ev.Ident)
	if ev.Filter == syscall.EVFILT_READ {
		mode = 'r'
	} else {
		mode = 'w'
	}
	return fd, mode, nil
}
예제 #7
0
파일: fileutil.go 프로젝트: joshix/acbuild
// TODO(sgotti) use UTIMES_OMIT on linux if Time.IsZero ?
func TimeToTimespec(time time.Time) (ts syscall.Timespec) {
	nsec := int64(0)
	if !time.IsZero() {
		nsec = time.UnixNano()
	}
	return syscall.NsecToTimespec(nsec)
}
예제 #8
0
func (p *pollster) Kevent(nsec int64) (result int, events []net_event, err error) {
	var t *syscall.Timespec
	if nsec > 0 {
		if t == nil {
			t = new(syscall.Timespec)
		}
		*t = syscall.NsecToTimespec(nsec)
	}
	n, err := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)

	if err != nil {
		if err == syscall.EINTR {
			return 0, nil, nil
		} else {
			return -1, nil, os.NewSyscallError("kevent", err)
		}
	}
	if n == 0 {
		return -2, nil, nil
	}
	events = make([]net_event, n)
	for i, ev := range p.eventbuf {
		events[i].fd = int(ev.Ident)
		events[i].data = int(ev.Data)
		if ev.Filter == syscall.EVFILT_READ {
			events[i].mode = 'r'
		} else {
			events[i].mode = 'w'
		}
	}
	return n, events, nil
}
예제 #9
0
func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
	var t *syscall.Timespec
	for len(p.events) == 0 {
		if nsec > 0 {
			if t == nil {
				t = new(syscall.Timespec)
			}
			*t = syscall.NsecToTimespec(nsec)
		}

		s.Unlock()
		n, err := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
		s.Lock()

		if err != nil {
			if err == syscall.EINTR {
				continue
			}
			return -1, 0, os.NewSyscallError("kevent", err)
		}
		if n == 0 {
			return -1, 0, nil
		}
		p.events = p.eventbuf[:n]
	}
	ev := &p.events[0]
	p.events = p.events[1:]
	fd = int(ev.Ident)
	if ev.Filter == syscall.EVFILT_READ {
		mode = 'r'
	} else {
		mode = 'w'
	}
	return fd, mode, nil
}
예제 #10
0
파일: node.go 프로젝트: ar-jan/restic
func (node Node) RestoreTimestamps(path string) error {
	var utimes = [...]syscall.Timespec{
		syscall.NsecToTimespec(node.AccessTime.UnixNano()),
		syscall.NsecToTimespec(node.ModTime.UnixNano()),
	}

	if node.Type == "symlink" {
		return node.restoreSymlinkTimestamps(path, utimes)
	}

	if err := syscall.UtimesNano(path, utimes[:]); err != nil {
		return errors.Wrap(err, "UtimesNano")
	}

	return nil
}
예제 #11
0
파일: time.go 프로젝트: lunixbochs/usercorn
func (k *PosixKernel) ClockGettime(_ int, out co.Obuf) uint64 {
	ts := syscall.NsecToTimespec(time.Now().UnixNano())
	err := out.Pack(&native.Timespec{int64(ts.Sec), int64(ts.Nsec)})
	if err != nil {
		return UINT64_MAX // FIXME
	}
	return 0
}
예제 #12
0
func LUtimesNano(path string, atime time.Time, mtime time.Time) error {
	var utimes [2]syscall.Timespec
	utimes[0] = syscall.NsecToTimespec(atime.UnixNano())
	utimes[1] = syscall.NsecToTimespec(mtime.UnixNano())

	var _path *byte
	_path, err := syscall.BytePtrFromString(path)
	if err != nil {
		return err
	}

	if _, _, err := syscall.Syscall(syscall.SYS_LUTIMES, uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&utimes[0])), 0); err != 0 {
		return &os.PathError{"chtimes", path, err}
	}

	return nil
}
예제 #13
0
파일: diff.go 프로젝트: neil-rubens/docker
func timeToTimespec(time time.Time) (ts syscall.Timespec) {
	if time.IsZero() {
		// Return UTIME_OMIT special value
		ts.Sec = 0
		ts.Nsec = ((1 << 30) - 2)
		return
	}
	return syscall.NsecToTimespec(time.UnixNano())
}
예제 #14
0
// Utimens - path based version of loopbackFile.Utimens()
func (fs *loopbackFileSystem) Utimens(path string, a *time.Time, m *time.Time, context *fuse.Context) (code fuse.Status) {
	var ts [2]syscall.Timespec

	if a == nil {
		ts[0].Nsec = _UTIME_OMIT
	} else {
		ts[0] = syscall.NsecToTimespec(a.UnixNano())
		ts[0].Nsec = 0
	}

	if m == nil {
		ts[1].Nsec = _UTIME_OMIT
	} else {
		ts[1] = syscall.NsecToTimespec(m.UnixNano())
		ts[1].Nsec = 0
	}

	err := sysUtimensat(0, fs.GetPath(path), &ts, _AT_SYMLINK_NOFOLLOW)
	return fuse.ToStatus(err)
}
예제 #15
0
파일: kqueue.go 프로젝트: rainycape/aio
func (p poller) timespec(d time.Duration) *C.struct_timespec {
	if d < 0 {
		// a NULL timespec tells kqueue to wait forever
		return nil
	}
	t := syscall.NsecToTimespec(d.Nanoseconds())
	// darwin defines tv_sec as __darwin_time_t, so we
	// need to to some indirection to let C do the implicit
	// type conversion.
	ts := C.make_timespec(C.long(t.Sec), C.long(t.Nsec))
	return &ts
}
예제 #16
0
파일: misc.go 프로젝트: rfjakob/go-fuse
// UtimeToTimespec converts a "Time" pointer as passed to Utimens to a
// "Timespec" that can be passed to the utimensat syscall.
// A nil pointer is converted to the special UTIME_OMIT value.
func UtimeToTimespec(t *time.Time) (ts syscall.Timespec) {
	if t == nil {
		ts.Nsec = _UTIME_OMIT
	} else {
		ts = syscall.NsecToTimespec(t.UnixNano())
		// Go bug https://github.com/golang/go/issues/12777
		if ts.Nsec < 0 {
			ts.Nsec = 0
		}
	}
	return ts
}
예제 #17
0
// Utimens - file handle based version of loopbackFileSystem.Utimens()
func (f *loopbackFile) Utimens(a *time.Time, m *time.Time) fuse.Status {
	var ts [2]syscall.Timespec

	if a == nil {
		ts[0].Nsec = _UTIME_OMIT
	} else {
		ts[0] = syscall.NsecToTimespec(a.UnixNano())
		ts[0].Nsec = 0
	}

	if m == nil {
		ts[1].Nsec = _UTIME_OMIT
	} else {
		ts[1] = syscall.NsecToTimespec(a.UnixNano())
		ts[1].Nsec = 0
	}

	f.lock.Lock()
	err := futimens(int(f.File.Fd()), &ts)
	f.lock.Unlock()
	return fuse.ToStatus(err)
}
예제 #18
0
func LUtimesNano(path string, atime time.Time, mtime time.Time) error {
	var utimes [2]syscall.Timespec
	utimes[0] = syscall.NsecToTimespec(atime.UnixNano())
	utimes[1] = syscall.NsecToTimespec(mtime.UnixNano())

	// These are not currently available in syscall
	AT_FDCWD := -100
	AT_SYMLINK_NOFOLLOW := 0x100

	var _path *byte
	_path, err := syscall.BytePtrFromString(path)
	if err != nil {
		return &os.PathError{"chtimes", path, err}
	}

	// Note this does depend on kernel 2.6.22 or newer.  Fallbacks are available but we haven't implemented them and they lose nano precision.
	if _, _, err := syscall.Syscall6(syscall.SYS_UTIMENSAT, uintptr(AT_FDCWD), uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&utimes[0])), uintptr(AT_SYMLINK_NOFOLLOW), 0, 0); err != 0 {
		return &os.PathError{"chtimes", path, err}
	}

	return nil
}
예제 #19
0
파일: time.go 프로젝트: SBkiller/usercorn
func (k *PosixKernel) ClockGettime(_ int, out co.Obuf) uint64 {
	var err error
	ts := syscall.NsecToTimespec(time.Now().UnixNano())
	if k.U.Bits() == 64 {
		err = out.Pack(&Timespec64{ts.Sec, ts.Nsec})
	} else {
		err = out.Pack(&Timespec{int32(ts.Sec), int32(ts.Nsec)})
	}
	if err != nil {
		return UINT64_MAX // FIXME
	}
	return 0
}
예제 #20
0
파일: utils.go 프로젝트: ziutek/eagle
func nanosleep(d time.Duration) {
	if d <= 0 {
		return
	}
	to := syscall.NsecToTimespec(int64(d))
	for {
		err := syscall.Nanosleep(&to, &to)
		if err == nil {
			return
		}
		if err != syscall.EINTR {
			dieErr(err)
		}
	}
}
예제 #21
0
//setCTime will set the create time on a file. On Windows, this requires
//calling SetFileTime and explicitly including the create time.
func setCTime(path string, ctime time.Time) error {
	ctimespec := syscall.NsecToTimespec(ctime.UnixNano())
	pathp, e := syscall.UTF16PtrFromString(path)
	if e != nil {
		return e
	}
	h, e := syscall.CreateFile(pathp,
		syscall.FILE_WRITE_ATTRIBUTES, syscall.FILE_SHARE_WRITE, nil,
		syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
	if e != nil {
		return e
	}
	defer syscall.Close(h)
	c := syscall.NsecToFiletime(syscall.TimespecToNsec(ctimespec))
	return syscall.SetFileTime(h, &c, nil, nil)
}
예제 #22
0
func (p *Poller) WaitWrite(deadline time.Time) error {

	// setup timeout
	var timeout *syscall.Timespec
	if !deadline.IsZero() {
		d := deadline.Sub(time.Now())
		t := syscall.NsecToTimespec(d.Nanoseconds())
		timeout = &t
	}

	// wait on kevent
	events := make([]syscall.Kevent_t, 1)
	n, err := syscall.Kevent(p.kqfd, []syscall.Kevent_t{p.event}, events, timeout)
	if err != nil {
		return err
	}

	if n < 1 {
		return errTimeout
	}
	return nil
}
예제 #23
0
// readEvents reads from the kqueue file descriptor, converts the
// received events into Event objects and sends them via the Event channel
func (this *watcher) doReadEvents(flags uint32, events chan<- IFSEvent, devNull chan<- error, done <-chan bool) {
	var (
		keventbuf [10]syscall.Kevent_t // Event buffer
		kevents   []syscall.Kevent_t   // Received events
		twait     *syscall.Timespec    // Time to block waiting for events
	)
	kevents = keventbuf[0:0]
	twait = new(syscall.Timespec)
	*twait = syscall.NsecToTimespec(keventWaitTime)

	for {
		// If "done" message is received
		select {
		case <-done:
			return
		default:

		}

		// Get new events
		if len(kevents) == 0 {
			n, errno := syscall.Kevent(this.kq, nil, keventbuf[:], twait)

			// EINTR is okay, basically the syscall was interrupted before
			// timeout expired.
			if errno != nil && errno != syscall.EINTR {
				devNull <- os.NewSyscallError("kevent", errno)
				continue
			}

			// Received some events
			if n > 0 {
				kevents = keventbuf[0:n]
			}
		}

		// Flush the events we received to the events channel
		for len(kevents) > 0 {
			fileEvent := new(FileEvent)
			watchEvent := &kevents[0]
			// Move to next event
			kevents = kevents[1:]

			fileEvent.mask = uint32(watchEvent.Fflags)
			info := this.watchedByFD[int(watchEvent.Ident)]
			if info != nil {
				fileEvent.Name = info.realPath
			}
			if info != nil && info.fInto.IsDir() && !fileEvent.IsDelete() {
				// Double check to make sure the directory exist. This can happen when
				// we do a rm -fr on a recursively watched folders and we receive a
				// modification event first but the folder has been deleted and later
				// receive the delete event
				if _, err := os.Lstat(fileEvent.Name); os.IsNotExist(err) {
					// mark is as delete event
					fileEvent.mask |= Note_DELETE
				}
			}

			if info != nil && info.fInto.IsDir() && fileEvent.IsModify() && !fileEvent.IsDelete() {
				this.sendDirectoryChangeEvents(info.realPath, info.flags, devNull, events)
			} else {
				// Send the event on the events channel
				if flags&fileEvent.mask != 0 || fileEvent.create {
					events <- fileEvent
				}
			}

			if fileEvent.IsDelete() {
				if err := this.doDel(fileEvent.Name); err != nil {
					devNull <- err
				}

				if _, err := os.Lstat(info.realPath); !os.IsNotExist(err) {
					this.sendDirectoryChangeEvents(info.realPath, flags, devNull, events)
				}
			} else if fileEvent.IsRename() {
				if err := this.doDel(fileEvent.Name); err != nil {
					devNull <- err
				}
			}

		}
	}
}
예제 #24
0
func calcCopyInfo(b *Builder, cmdName string, cInfos *[]*copyInfo, origPath string, destPath string, allowRemote bool, allowDecompression bool) error {

	if origPath != "" && origPath[0] == '/' && len(origPath) > 1 {
		origPath = origPath[1:]
	}
	origPath = strings.TrimPrefix(origPath, "./")

	// Twiddle the destPath when its a relative path - meaning, make it
	// relative to the WORKINGDIR
	if !filepath.IsAbs(destPath) {
		hasSlash := strings.HasSuffix(destPath, "/")
		destPath = filepath.Join("/", b.Config.WorkingDir, destPath)

		// Make sure we preserve any trailing slash
		if hasSlash {
			destPath += "/"
		}
	}

	// In the remote/URL case, download it and gen its hashcode
	if urlutil.IsURL(origPath) {
		if !allowRemote {
			return fmt.Errorf("Source can't be a URL for %s", cmdName)
		}

		ci := copyInfo{}
		ci.origPath = origPath
		ci.hash = origPath // default to this but can change
		ci.destPath = destPath
		ci.decompress = false
		*cInfos = append(*cInfos, &ci)

		// Initiate the download
		resp, err := utils.Download(ci.origPath)
		if err != nil {
			return err
		}

		// Create a tmp dir
		tmpDirName, err := ioutil.TempDir(b.contextPath, "docker-remote")
		if err != nil {
			return err
		}
		ci.tmpDir = tmpDirName

		// Create a tmp file within our tmp dir
		tmpFileName := path.Join(tmpDirName, "tmp")
		tmpFile, err := os.OpenFile(tmpFileName, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
		if err != nil {
			return err
		}

		// Download and dump result to tmp file
		if _, err := io.Copy(tmpFile, utils.ProgressReader(resp.Body, int(resp.ContentLength), b.OutOld, b.StreamFormatter, true, "", "Downloading")); err != nil {
			tmpFile.Close()
			return err
		}
		fmt.Fprintf(b.OutStream, "\n")
		tmpFile.Close()

		// Set the mtime to the Last-Modified header value if present
		// Otherwise just remove atime and mtime
		times := make([]syscall.Timespec, 2)

		lastMod := resp.Header.Get("Last-Modified")
		if lastMod != "" {
			mTime, err := http.ParseTime(lastMod)
			// If we can't parse it then just let it default to 'zero'
			// otherwise use the parsed time value
			if err == nil {
				times[1] = syscall.NsecToTimespec(mTime.UnixNano())
			}
		}

		if err := system.UtimesNano(tmpFileName, times); err != nil {
			return err
		}

		ci.origPath = path.Join(filepath.Base(tmpDirName), filepath.Base(tmpFileName))

		// If the destination is a directory, figure out the filename.
		if strings.HasSuffix(ci.destPath, "/") {
			u, err := url.Parse(origPath)
			if err != nil {
				return err
			}
			path := u.Path
			if strings.HasSuffix(path, "/") {
				path = path[:len(path)-1]
			}
			parts := strings.Split(path, "/")
			filename := parts[len(parts)-1]
			if filename == "" {
				return fmt.Errorf("cannot determine filename from url: %s", u)
			}
			ci.destPath = ci.destPath + filename
		}

		// Calc the checksum, even if we're using the cache
		r, err := archive.Tar(tmpFileName, archive.Uncompressed)
		if err != nil {
			return err
		}
		tarSum, err := tarsum.NewTarSum(r, true, tarsum.Version0)
		if err != nil {
			return err
		}
		if _, err := io.Copy(ioutil.Discard, tarSum); err != nil {
			return err
		}
		ci.hash = tarSum.Sum(nil)
		r.Close()

		return nil
	}

	// Deal with wildcards
	if ContainsWildcards(origPath) {
		for _, fileInfo := range b.context.GetSums() {
			if fileInfo.Name() == "" {
				continue
			}
			match, _ := path.Match(origPath, fileInfo.Name())
			if !match {
				continue
			}

			calcCopyInfo(b, cmdName, cInfos, fileInfo.Name(), destPath, allowRemote, allowDecompression)
		}
		return nil
	}

	// Must be a dir or a file

	if err := b.checkPathForAddition(origPath); err != nil {
		return err
	}
	fi, _ := os.Stat(path.Join(b.contextPath, origPath))

	ci := copyInfo{}
	ci.origPath = origPath
	ci.hash = origPath
	ci.destPath = destPath
	ci.decompress = allowDecompression
	*cInfos = append(*cInfos, &ci)

	// Deal with the single file case
	if !fi.IsDir() {
		// This will match first file in sums of the archive
		fis := b.context.GetSums().GetFile(ci.origPath)
		if fis != nil {
			ci.hash = "file:" + fis.Sum()
		}
		return nil
	}

	// Must be a dir
	var subfiles []string
	absOrigPath := path.Join(b.contextPath, ci.origPath)

	// Add a trailing / to make sure we only pick up nested files under
	// the dir and not sibling files of the dir that just happen to
	// start with the same chars
	if !strings.HasSuffix(absOrigPath, "/") {
		absOrigPath += "/"
	}

	// Need path w/o / too to find matching dir w/o trailing /
	absOrigPathNoSlash := absOrigPath[:len(absOrigPath)-1]

	for _, fileInfo := range b.context.GetSums() {
		absFile := path.Join(b.contextPath, fileInfo.Name())
		// Any file in the context that starts with the given path will be
		// picked up and its hashcode used.  However, we'll exclude the
		// root dir itself.  We do this for a coupel of reasons:
		// 1 - ADD/COPY will not copy the dir itself, just its children
		//     so there's no reason to include it in the hash calc
		// 2 - the metadata on the dir will change when any child file
		//     changes.  This will lead to a miss in the cache check if that
		//     child file is in the .dockerignore list.
		if strings.HasPrefix(absFile, absOrigPath) && absFile != absOrigPathNoSlash {
			subfiles = append(subfiles, fileInfo.Sum())
		}
	}
	sort.Strings(subfiles)
	hasher := sha256.New()
	hasher.Write([]byte(strings.Join(subfiles, ",")))
	ci.hash = "dir:" + hex.EncodeToString(hasher.Sum(nil))

	return nil
}
예제 #25
0
// readEvents reads from the kqueue file descriptor, converts the
// received events into Event objects and sends them via the Event channel
func (w *Watcher) readEvents() {
	var (
		eventbuf [10]syscall.Kevent_t // Event buffer
		events   []syscall.Kevent_t   // Received events
		twait    *syscall.Timespec    // Time to block waiting for events
		n        int                  // Number of events returned from kevent
		errno    error                // Syscall errno
	)
	events = eventbuf[0:0]
	twait = new(syscall.Timespec)
	*twait = syscall.NsecToTimespec(keventWaitTime)

	for {
		// See if there is a message on the "done" channel
		var done bool
		select {
		case done = <-w.done:
		default:
		}

		// If "done" message is received
		if done {
			errno := syscall.Close(w.kq)
			if errno != nil {
				w.Error <- os.NewSyscallError("close", errno)
			}
			close(w.internalEvent)
			close(w.Error)
			return
		}

		// Get new events
		if len(events) == 0 {
			n, errno = syscall.Kevent(w.kq, nil, eventbuf[:], twait)

			// EINTR is okay, basically the syscall was interrupted before
			// timeout expired.
			if errno != nil && errno != syscall.EINTR {
				w.Error <- os.NewSyscallError("kevent", errno)
				continue
			}

			// Received some events
			if n > 0 {
				events = eventbuf[0:n]
			}
		}

		// Flush the events we recieved to the events channel
		for len(events) > 0 {
			fileEvent := new(FileEvent)
			watchEvent := &events[0]
			fileEvent.mask = uint32(watchEvent.Fflags)
			fileEvent.Name = w.paths[int(watchEvent.Ident)]

			fileInfo := w.finfo[int(watchEvent.Ident)]
			if fileInfo.IsDir() && fileEvent.IsModify() {
				w.sendDirectoryChangeEvents(fileEvent.Name)
			} else {
				// Send the event on the events channel
				w.internalEvent <- fileEvent
			}

			// Move to next event
			events = events[1:]

			if fileEvent.IsRename() {
				w.removeWatch(fileEvent.Name)
				delete(w.fileExists, fileEvent.Name)
			}
			if fileEvent.IsDelete() {
				w.removeWatch(fileEvent.Name)
				delete(w.fileExists, fileEvent.Name)
			}
		}
	}
}
예제 #26
0
func (s statWin) mtim() syscall.Timespec {
	return syscall.NsecToTimespec(s.LastWriteTime.Nanoseconds())
}
예제 #27
0
func (s statWin) atim() syscall.Timespec {
	return syscall.NsecToTimespec(s.LastAccessTime.Nanoseconds())
}
예제 #28
0
// readEvents reads from the kqueue file descriptor, converts the
// received events into Event objects and sends them via the Event channel
func (w *Watcher) readEvents() {
	var (
		eventbuf [10]syscall.Kevent_t // Event buffer
		events   []syscall.Kevent_t   // Received events
		twait    *syscall.Timespec    // Time to block waiting for events
		n        int                  // Number of events returned from kevent
		errno    error                // Syscall errno
	)
	events = eventbuf[0:0]
	twait = new(syscall.Timespec)
	*twait = syscall.NsecToTimespec(keventWaitTime)

	for {
		// See if there is a message on the "done" channel
		var done bool
		select {
		case done = <-w.done:
		default:
		}

		// If "done" message is received
		if done {
			errno := syscall.Close(w.kq)
			if errno != nil {
				w.Error <- os.NewSyscallError("close", errno)
			}
			close(w.internalEvent)
			close(w.Error)
			return
		}

		// Get new events
		if len(events) == 0 {
			n, errno = syscall.Kevent(w.kq, nil, eventbuf[:], twait)

			// EINTR is okay, basically the syscall was interrupted before
			// timeout expired.
			if errno != nil && errno != syscall.EINTR {
				w.Error <- os.NewSyscallError("kevent", errno)
				continue
			}

			// Received some events
			if n > 0 {
				events = eventbuf[0:n]
			}
		}

		// Flush the events we recieved to the events channel
		for len(events) > 0 {
			fileEvent := new(FileEvent)
			watchEvent := &events[0]
			fileEvent.mask = uint32(watchEvent.Fflags)
			fileEvent.Name = w.paths[int(watchEvent.Ident)]

			fileInfo := w.finfo[int(watchEvent.Ident)]
			if fileInfo.IsDir() && !fileEvent.IsDelete() {
				// Double check to make sure the directory exist. This can happen when
				// we do a rm -fr on a recursively watched folders and we receive a
				// modification event first but the folder has been deleted and later
				// receive the delete event
				if _, err := os.Lstat(fileEvent.Name); os.IsNotExist(err) {
					// mark is as delete event
					fileEvent.mask |= NOTE_DELETE
				}
			}

			if fileInfo.IsDir() && fileEvent.IsModify() && !fileEvent.IsDelete() {
				w.sendDirectoryChangeEvents(fileEvent.Name)
			} else {
				// Send the event on the events channel
				w.internalEvent <- fileEvent
			}

			// Move to next event
			events = events[1:]

			if fileEvent.IsRename() {
				w.removeWatch(fileEvent.Name)
				delete(w.fileExists, fileEvent.Name)
			}
			if fileEvent.IsDelete() {
				w.removeWatch(fileEvent.Name)
				delete(w.fileExists, fileEvent.Name)

				// Look for a file that may have overwritten this
				// (ie mv f1 f2 will delete f2 then create f2)
				fileDir, _ := filepath.Split(fileEvent.Name)
				fileDir = filepath.Clean(fileDir)
				if _, found := w.watches[fileDir]; found {
					// make sure the directory exist before we watch for changes. When we
					// do a recursive watch and perform rm -fr, the parent directory might
					// have gone missing, ignore the missing directory and let the
					// upcoming delete event remove the watch form the parent folder
					if _, err := os.Lstat(fileDir); !os.IsNotExist(err) {
						w.sendDirectoryChangeEvents(fileDir)
					}
				}
			}
		}
	}
}
예제 #29
0
파일: kqueue.go 프로젝트: noonat/runit
// durationToTimespec prepares a timeout value
func durationToTimespec(d time.Duration) syscall.Timespec {
	return syscall.NsecToTimespec(d.Nanoseconds())
}
예제 #30
0
func (s statWin) ctim() syscall.Timespec {
	return syscall.NsecToTimespec(s.CreationTime.Nanoseconds())
}