Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion windows/registry/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,20 @@ type KeyInfo struct {

// ModTime returns the key's last write time.
func (ki *KeyInfo) ModTime() time.Time {
return time.Unix(0, ki.lastWriteTime.Nanoseconds())
lastHigh, lastLow := ki.lastWriteTime.HighDateTime, ki.lastWriteTime.LowDateTime
// 100-nanosecond intervals since January 1, 1601
hsec := uint64(lastHigh)<<32 + uint64(lastLow)
// Convert _before_ gauging; the nanosecond difference between Epoch (00:00:00
// UTC, January 1, 1970) and Filetime's zero offset (January 1, 1601) is out
// of bounds for int64: -11644473600*1e7*1e2 < math.MinInt64
sec := int64(hsec/1e7) - 11644473600
nsec := int64(hsec%1e7) * 100
return time.Unix(sec, nsec)
}

// ModTimeZero reports whether the key's last write time is zero.
func (ki *KeyInfo) ModTimeZero() bool {
return ki.lastWriteTime.LowDateTime == 0 && ki.lastWriteTime.HighDateTime == 0
}

// Stat retrieves information about the open key k.
Expand Down
28 changes: 28 additions & 0 deletions windows/registry/registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package registry_test
import (
"bytes"
"crypto/rand"
"errors"
"os"
"syscall"
"testing"
Expand Down Expand Up @@ -674,3 +675,30 @@ func GetDynamicTimeZoneInformation(dtzi *DynamicTimezoneinformation) (rc uint32,
}
return
}

func TestModTimeZeroValue(t *testing.T) {
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009`, registry.READ)
if err != nil {
if errors.Is(err, syscall.ERROR_FILE_NOT_FOUND) {
t.Skip("Perflib key not found; skipping")
}
t.Fatal(err)
}
defer k.Close()

// Modification time of Perflib keys is known to be set to
// Filetime's zero value: get stats and check.
stats, err := k.Stat()
if err != nil {
t.Fatal(err)
}
// First verify input is zero (assume ModTimeZero uses it directly).
if !stats.ModTimeZero() {
t.Error("Modification time of Perflib key should be zero")
}
// Then check ModTime directly thus conversion implicitly.
modTime := stats.ModTime()
if !modTime.Equal(time.Date(1601, time.January, 1, 0, 0, 0, 0, time.UTC)) {
t.Errorf("ModTime should be 1601-01-01, but is %v", modTime)
}
}