Skip to content
Merged
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
27 changes: 21 additions & 6 deletions fatfs/go_fatfs_callbacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,30 @@ func go_fatfs_disk_ioctl(drv unsafe.Pointer, cmd uint8, param unsafe.Pointer) in

//export go_fatfs_get_fattime
func go_fatfs_get_fattime() (t uint32) {
const (
epochYear = 1980 // years are stored as an offset from 1980
yearShift = 25 // year offset, bits 25-31
monthShift = 21 // month, bits 21-24
dayShift = 16 // day of month, bits 16-20
hourShift = 11 // hour, bits 11-15
minuteShift = 5 // minute, bits 5-10
monthMask = 0x0f // month, 4 bits
dayMask = 0x1f // day of month, 5 bits
hourMask = 0x1f // hour, 5 bits
minuteMask = 0x3f // minute, 6 bits
secondMask = 0x1f // two-second units, 5 bits
secondsPerUnit = 2 // FAT timestamps have two-second resolution
)

now := time.Now()
year, month, day := now.Date()
hour, minute, second := now.Hour(), now.Minute(), now.Second()
t |= uint32(year-1980) << 24
t |= (uint32(month) & 0xF) << 20
t |= (uint32(day) & 0x1F) << 15
t |= (uint32(hour) & 0x1F) << 10
t |= (uint32(minute) & 0x3F) << 4
t |= (uint32(second) / 2) & 0xF
t |= uint32(year-epochYear) << yearShift
t |= (uint32(month) & monthMask) << monthShift
t |= (uint32(day) & dayMask) << dayShift
t |= (uint32(hour) & hourMask) << hourShift
t |= (uint32(minute) & minuteMask) << minuteShift
t |= (uint32(second) / secondsPerUnit) & secondMask
return t
}

Expand Down
37 changes: 37 additions & 0 deletions fatfs/go_fatfs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
package fatfs

import (
"encoding/binary"
"os"
"testing"
"time"

"tinygo.org/x/tinyfs"
)
Expand All @@ -15,6 +17,41 @@ const (
testBlockCount = 4096
)

func TestStoredModificationTime(t *testing.T) {
fs, dev, unmount := createTestFS(t)
defer unmount()
if typ := Type(fs.fs.fs_type); typ != TypeFAT12 && typ != TypeFAT16 {
t.Fatalf("expected FAT12 or FAT16, got %s", typ)
}
before := time.Now().Truncate(2 * time.Second)
f, err := fs.OpenFile("TIME.TXT", os.O_CREATE|os.O_WRONLY|os.O_TRUNC)
check(t, err)
_, err = f.Write([]byte("timestamp"))
check(t, err)
check(t, f.Close())
after := time.Now()

root := make([]byte, int(fs.fs.n_rootdir)*32)
_, err = dev.ReadAt(root, int64(fs.fs.dirbase)*SectorSize)
check(t, err)
for offset := 0; offset < len(root); offset += 32 {
entry := root[offset : offset+32]
if string(entry[:11]) != "TIME TXT" {
continue
}
// FAT directory entries store modification time at bytes 22-25.
clock := binary.LittleEndian.Uint16(entry[22:24])
date := binary.LittleEndian.Uint16(entry[24:26])
got := time.Date(1980+int(date>>9), time.Month(date>>5&15), int(date&31),
int(clock>>11), int(clock>>5&63), int(clock&31)*2, 0, time.Local)
if got.Before(before) || got.After(after) {
t.Fatalf("stored modification time = %s, want between %s and %s", got, before, after)
}
return
}
t.Fatal("TIME.TXT not found in root directory")
}

func TestType_String(t *testing.T) {
expectString(t, "fatfs: (1) A hard error occurred in the low level disk I/O layer", FileResultErr.Error())
}
Expand Down
Loading