├── LICENSE.rst ├── README.rst ├── extstat.go ├── extstat_darwin.go ├── extstat_dragonfly.go ├── extstat_freebsd.go ├── extstat_linux.go ├── extstat_nacl.go ├── extstat_netbsd.go ├── extstat_openbsd.go ├── extstat_plan9.go ├── extstat_solaris.go ├── extstat_test.go └── extstat_windows.go /LICENSE.rst: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ======================= 3 | 4 | Copyright (c) 2015 Yoshiki Shibukawa 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ExtraStat 2 | ============ 3 | 4 | This is inspired by `atime by Dustin H `_, and add creation time to return. 5 | 6 | License 7 | --------- 8 | 9 | MIT 10 | -------------------------------------------------------------------------------- /extstat.go: -------------------------------------------------------------------------------- 1 | package extstat 2 | 3 | import ( 4 | "os" 5 | "time" 6 | ) 7 | 8 | type ExtraStat struct { 9 | AccessTime time.Time 10 | ModTime time.Time 11 | ChangeTime time.Time 12 | BirthTime time.Time 13 | } 14 | 15 | func NewFromFileName(name string) (*ExtraStat, error) { 16 | fi, err := os.Stat(name) 17 | if err != nil { 18 | return nil, err 19 | } 20 | return New(fi), nil 21 | } 22 | -------------------------------------------------------------------------------- /extstat_darwin.go: -------------------------------------------------------------------------------- 1 | package extstat 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "time" 7 | ) 8 | 9 | func timespecToTime(ts syscall.Timespec) time.Time { 10 | return time.Unix(int64(ts.Sec), int64(ts.Nsec)) 11 | } 12 | 13 | func New(fi os.FileInfo) *ExtraStat { 14 | osStat := fi.Sys().(*syscall.Stat_t) 15 | return &ExtraStat{ 16 | AccessTime: timespecToTime(osStat.Atimespec), 17 | ModTime: fi.ModTime(), 18 | ChangeTime: timespecToTime(osStat.Ctimespec), 19 | BirthTime: timespecToTime(osStat.Birthtimespec), 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /extstat_dragonfly.go: -------------------------------------------------------------------------------- 1 | package extstat 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "time" 7 | ) 8 | 9 | func timespecToTime(ts syscall.Timespec) time.Time { 10 | return time.Unix(int64(ts.Sec), int64(ts.Nsec)) 11 | } 12 | 13 | func New(fi os.FileInfo) *ExtraStat { 14 | osStat := fi.Sys().(*syscall.Stat_t) 15 | return &ExtraStat{ 16 | AccessTime: timespecToTime(osStat.Atim), 17 | ModTime: fi.ModTime(), 18 | ChangeTime: timespecToTime(osStat.Ctim), 19 | BirthTime: fi.ModTime(), 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /extstat_freebsd.go: -------------------------------------------------------------------------------- 1 | package extstat 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "time" 7 | ) 8 | 9 | func timespecToTime(ts syscall.Timespec) time.Time { 10 | return time.Unix(int64(ts.Sec), int64(ts.Nsec)) 11 | } 12 | 13 | func New(fi os.FileInfo) *ExtraStat { 14 | osStat := fi.Sys().(*syscall.Stat_t) 15 | return &ExtraStat{ 16 | AccessTime: timespecToTime(osStat.Atimespec), 17 | ModTime: fi.ModTime(), 18 | ChangeTime: timespecToTime(osStat.Ctimespec), 19 | BirthTime: timespecToTime(osStat.Birthtimespec), 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /extstat_linux.go: -------------------------------------------------------------------------------- 1 | package extstat 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "time" 7 | ) 8 | 9 | func timespecToTime(ts syscall.Timespec) time.Time { 10 | return time.Unix(int64(ts.Sec), int64(ts.Nsec)) 11 | } 12 | 13 | func New(fi os.FileInfo) *ExtraStat { 14 | osStat := fi.Sys().(*syscall.Stat_t) 15 | return &ExtraStat{ 16 | AccessTime: timespecToTime(osStat.Atim), 17 | ModTime: fi.ModTime(), 18 | ChangeTime: timespecToTime(osStat.Ctim), 19 | BirthTime: fi.ModTime(), 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /extstat_nacl.go: -------------------------------------------------------------------------------- 1 | package extstat 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "time" 7 | ) 8 | 9 | func timespecToTime(sec, nsec int64) time.Time { 10 | return time.Unix(sec, nsec) 11 | } 12 | 13 | func New(fi os.FileInfo) *ExtraStat { 14 | osStat := fi.Sys().(*syscall.Stat_t) 15 | return &ExtraStat{ 16 | AccessTime: timespecToTime(osStat.Atime, osStat.AtimeNsec), 17 | ModTime: fi.ModTime(), 18 | ChangeTime: timespecToTime(osStat.Ctime, osStat.CtimeNsec), 19 | BirthTime: fi.ModTime(), 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /extstat_netbsd.go: -------------------------------------------------------------------------------- 1 | package extstat 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "time" 7 | ) 8 | 9 | func timespecToTime(ts syscall.Timespec) time.Time { 10 | return time.Unix(int64(ts.Sec), int64(ts.Nsec)) 11 | } 12 | 13 | func New(fi os.FileInfo) *ExtraStat { 14 | osStat := fi.Sys().(*syscall.Stat_t) 15 | return &ExtraStat{ 16 | AccessTime: timespecToTime(osStat.Atimespec), 17 | ModTime: fi.ModTime(), 18 | ChangeTime: timespecToTime(osStat.Ctimespec), 19 | BirthTime: timespecToTime(osStat.Birthtimespec), 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /extstat_openbsd.go: -------------------------------------------------------------------------------- 1 | package extstat 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "time" 7 | ) 8 | 9 | func timespecToTime(ts syscall.Timespec) time.Time { 10 | return time.Unix(int64(ts.Sec), int64(ts.Nsec)) 11 | } 12 | 13 | func New(fi os.FileInfo) *ExtraStat { 14 | osStat := fi.Sys().(*syscall.Stat_t) 15 | return &ExtraStat{ 16 | AccessTime: timespecToTime(osStat.Atim), 17 | ModTime: fi.ModTime(), 18 | ChangeTime: timespecToTime(osStat.Ctim), 19 | BirthTime: fi.ModTime(), 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /extstat_plan9.go: -------------------------------------------------------------------------------- 1 | package extstat 2 | 3 | import ( 4 | "os" 5 | "time" 6 | ) 7 | 8 | func New(fi os.FileInfo) *ExtraStat { 9 | return &ExtraStat{ 10 | AccessTime: time.Unix(int64(fi.Sys().(*syscall.Dir).Atime), 0), 11 | ModTime: fi.ModTime(), 12 | ChangeTime: fi.ModTime(), 13 | BirthTime: fi.ModTime(), 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /extstat_solaris.go: -------------------------------------------------------------------------------- 1 | package extstat 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "time" 7 | ) 8 | 9 | func timespecToTime(ts syscall.Timespec) time.Time { 10 | return time.Unix(int64(ts.Sec), int64(ts.Nsec)) 11 | } 12 | 13 | func New(fi os.FileInfo) *ExtraStat { 14 | osStat := fi.Sys().(*syscall.Stat_t) 15 | return &ExtraStat{ 16 | AccessTime: timespecToTime(osStat.Atim), 17 | ModTime: fi.ModTime(), 18 | ChangeTime: timespecToTime(osStat.Ctim), 19 | BirthTime: fi.ModTime(), 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /extstat_test.go: -------------------------------------------------------------------------------- 1 | package extstat 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "runtime" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | var filePath string = "test.txt" 12 | 13 | func TestNew(t *testing.T) { 14 | err := ioutil.WriteFile(filePath, []byte("hello"), 0666) 15 | if err != nil { 16 | t.Error(err) 17 | return 18 | } 19 | defer os.Remove(filePath) 20 | now := time.Now() 21 | 22 | btimeBefore := now.Add(+time.Second) 23 | btimeAfter := now.Add(-time.Second) 24 | mtimeBefore := now.Add(time.Second * 4) 25 | mtimeAfter := now.Add(time.Second * 2) 26 | atimeBefore := now.Add(time.Second * 7) 27 | atimeAfter := now.Add(time.Second * 5) 28 | 29 | t.Log("wait for changing mtime...") 30 | time.Sleep(time.Second * 3) 31 | fileForModify, err := os.OpenFile(filePath, os.O_WRONLY|os.O_APPEND, 0666) 32 | if err != nil { 33 | fileForModify.Close() 34 | t.Error(err) 35 | return 36 | } 37 | fileForModify.Write([]byte(" world")) 38 | fileForModify.Close() 39 | 40 | t.Log("wait for changing atime...") 41 | time.Sleep(time.Second * 3) 42 | content, err := ioutil.ReadFile(filePath) 43 | t.Log(string(content)) 44 | if err != nil { 45 | t.Error(err) 46 | return 47 | } 48 | 49 | stat, err := os.Stat(filePath) 50 | if err != nil { 51 | t.Error(err) 52 | return 53 | } 54 | 55 | extStat := New(stat) 56 | 57 | // plan9 doesn't have correct ctime attribute 58 | if runtime.GOOS != "plan9" { 59 | if !extStat.BirthTime.Before(btimeBefore) || !extStat.BirthTime.After(btimeAfter) { 60 | t.Error("btime is wrong:", btimeAfter, "<", extStat.BirthTime, "<", btimeBefore, " now: ", now) 61 | } 62 | } 63 | if !extStat.ModTime.Before(mtimeBefore) || !extStat.ModTime.After(mtimeAfter) { 64 | t.Error("mtime is wrong:", mtimeAfter, "<", extStat.ModTime, "<", mtimeBefore, " now: ", now) 65 | } 66 | if !extStat.ModTime.Before(mtimeBefore) || !extStat.ChangeTime.After(mtimeAfter) { 67 | t.Error("mtime is wrong:", mtimeAfter, "<", extStat.ModTime, "<", mtimeBefore, " now: ", now) 68 | } 69 | if !extStat.AccessTime.Before(atimeBefore) || !extStat.AccessTime.After(atimeAfter) { 70 | t.Error("atime is wrong:", atimeAfter, "<", extStat.AccessTime, "<", atimeBefore, " now: ", now) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /extstat_windows.go: -------------------------------------------------------------------------------- 1 | package extstat 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "time" 7 | ) 8 | 9 | func New(fi os.FileInfo) *ExtraStat { 10 | dateAttribute := fi.Sys().(*syscall.Win32FileAttributeData) 11 | return &ExtraStat{ 12 | AccessTime: time.Unix(0, dateAttribute.LastAccessTime.Nanoseconds()), 13 | ModTime: fi.ModTime(), 14 | ChangeTime: fi.ModTime(), 15 | BirthTime: time.Unix(0, dateAttribute.CreationTime.Nanoseconds()), 16 | } 17 | } 18 | --------------------------------------------------------------------------------