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) } }
func setZeroModTime(filename string) error { var utimes = []syscall.Timespec{ syscall.NsecToTimespec(0), syscall.NsecToTimespec(0), } return syscall.UtimesNano(filename, utimes) }
// 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 }
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 }
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 }
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 }
// 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) }
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 }
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 }
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 }
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 }
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 }
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()) }
// 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) }
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 }
// 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 }
// 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) }
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 }
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 }
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) } } }
//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) }
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 }
// 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 } } } } }
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 }
// 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) } } } }
func (s statWin) mtim() syscall.Timespec { return syscall.NsecToTimespec(s.LastWriteTime.Nanoseconds()) }
func (s statWin) atim() syscall.Timespec { return syscall.NsecToTimespec(s.LastAccessTime.Nanoseconds()) }
// 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) } } } } } }
// durationToTimespec prepares a timeout value func durationToTimespec(d time.Duration) syscall.Timespec { return syscall.NsecToTimespec(d.Nanoseconds()) }
func (s statWin) ctim() syscall.Timespec { return syscall.NsecToTimespec(s.CreationTime.Nanoseconds()) }