diff --git a/pkg/manager/crash.go b/pkg/manager/crash.go index a62ec8280125..e537cdf60284 100644 --- a/pkg/manager/crash.go +++ b/pkg/manager/crash.go @@ -235,7 +235,7 @@ func (cs *CrashStore) BugInfo(id string, full bool) (*BugInfo, error) { if err != nil { return nil, err } - stat, err := os.Stat(filepath.Join(dir, "description")) + ret.FirstTime, ret.LastTime, err = osutil.FileTimes(filepath.Join(dir, "description")) if err != nil { return nil, err } @@ -250,8 +250,6 @@ func (cs *CrashStore) BugInfo(id string, full bool) (*BugInfo, error) { } } - ret.FirstTime = osutil.CreationTime(stat) - ret.LastTime = stat.ModTime() files, err := osutil.ListDir(dir) if err != nil { return nil, err diff --git a/pkg/osutil/osutil.go b/pkg/osutil/osutil.go index fa963a3fbbae..d566827325d6 100644 --- a/pkg/osutil/osutil.go +++ b/pkg/osutil/osutil.go @@ -351,10 +351,9 @@ func Abs(path string) string { return filepath.Clean(path) } -// CreationTime returns file creation time. -// May return zero time, if not known. -func CreationTime(fi os.FileInfo) time.Time { - return creationTime(fi) +// FileTimes returns file creation and modification times. +func FileTimes(file string) (time.Time, time.Time, error) { + return fileTimes(file) } // MonotonicNano returns monotonic time in nanoseconds from some unspecified point in time. diff --git a/pkg/osutil/osutil_linux.go b/pkg/osutil/osutil_linux.go index 50be9b047282..5ab63928095f 100644 --- a/pkg/osutil/osutil_linux.go +++ b/pkg/osutil/osutil_linux.go @@ -18,9 +18,20 @@ import ( "golang.org/x/sys/unix" ) -func creationTime(fi os.FileInfo) time.Time { - st := fi.Sys().(*syscall.Stat_t) - return time.Unix(int64(st.Ctim.Sec), int64(st.Ctim.Nsec)) // nolint: unconvert +func fileTimes(file string) (time.Time, time.Time, error) { + // Btime stands for "birth" time, which is creation time. + var statx unix.Statx_t + err := unix.Statx(unix.AT_FDCWD, file, unix.AT_SYMLINK_NOFOLLOW, unix.STATX_BTIME|unix.STATX_MTIME, &statx) + if err != nil { + return time.Time{}, time.Time{}, err + } + modTime := time.Unix(statx.Mtime.Sec, int64(statx.Mtime.Nsec)) + // Some filesystems may not store the birth time. + creationTime := modTime + if statx.Mask&unix.STATX_BTIME != 0 { + creationTime = time.Unix(statx.Btime.Sec, int64(statx.Btime.Nsec)) + } + return creationTime, modTime, nil } // RemoveAll is similar to os.RemoveAll, but can handle more cases. diff --git a/pkg/osutil/osutil_nonlinux.go b/pkg/osutil/osutil_nonlinux.go index 1d3ee8b82f03..bc696d3fc291 100644 --- a/pkg/osutil/osutil_nonlinux.go +++ b/pkg/osutil/osutil_nonlinux.go @@ -12,8 +12,14 @@ import ( "time" ) -func creationTime(fi os.FileInfo) time.Time { - return time.Time{} +func fileTimes(file string) (time.Time, time.Time, error) { + stat, err := os.Stat(file) + if err != nil { + return time.Time{}, time.Time{}, err + } + // Creation time is not present in stat, so we use modification time for both. + modTime := stat.ModTime() + return modTime, modTime, nil } func RemoveAll(dir string) error {