github.com/Cloud-Foundations/Dominator@v0.3.4/imagebuilder/builder/calibrateCtime.go (about) 1 package builder 2 3 import ( 4 "errors" 5 "io/ioutil" 6 "os" 7 "sync" 8 "syscall" 9 "time" 10 ) 11 12 var ( 13 calibrateOnce sync.Once 14 calibrationError error 15 _ctimeResolution time.Duration 16 ) 17 18 // calibrateCtime will calibrate the resolution of inode change times for 19 // temporary files. It will return the minimum resolution or an error. 20 func calibrateCtime() (time.Duration, error) { 21 buffer := []byte("data\n") 22 file, err := ioutil.TempFile("", "ctimeCalibration") 23 if err != nil { 24 return 0, err 25 } 26 defer file.Close() 27 defer os.Remove(file.Name()) 28 fd := int(file.Fd()) // Bypass os.File overheads. 29 if _, err := syscall.Write(fd, buffer); err != nil { 30 return 0, err 31 } 32 var firstStat syscall.Stat_t 33 if err := syscall.Stat(file.Name(), &firstStat); err != nil { 34 return 0, err 35 } 36 interval := time.Nanosecond 37 startTime := time.Now() 38 for ; time.Since(startTime) < time.Second; interval *= 10 { 39 if _, err := syscall.Write(fd, buffer); err != nil { 40 return 0, err 41 } 42 var newStat syscall.Stat_t 43 if err := syscall.Stat(file.Name(), &newStat); err != nil { 44 return 0, err 45 } 46 if newStat.Ctim != firstStat.Ctim { 47 return time.Since(startTime), nil 48 } 49 time.Sleep(interval) 50 } 51 return 0, errors.New("timed out calibrating Ctime changes") 52 } 53 54 func getCtimeResolution() (time.Duration, error) { 55 calibrateOnce.Do(func() { 56 _ctimeResolution, calibrationError = calibrateCtime() 57 }) 58 return _ctimeResolution, calibrationError 59 }