@@ -195,31 +195,29 @@ func inodeFromBytes(b []byte, sb *superblock, number uint32) (*inode, error) {
195195 // Thus, the full 64-bit timestamp value is constructed as follows:
196196 // original 32 bits (0:4) are seconds. Add (to the left) 2 more bits from the 32
197197 // the remaining 30 bites are nanoseconds
198- accessTimeSeconds := uint64 (binary .LittleEndian .Uint32 (b [0x8 :0xc ]))
199- changeTimeSeconds := uint64 (binary .LittleEndian .Uint32 (b [0xc :0x10 ]))
200- modifyTimeSeconds := uint64 (binary .LittleEndian .Uint32 (b [0x10 :0x14 ]))
201- createTimeSeconds := uint64 (binary .LittleEndian .Uint32 (b [0x90 :0x94 ]))
202-
203- accessTimeExtra := uint64 (binary .LittleEndian .Uint32 (b [0x8c :0x90 ]))
204- changeTimeExtra := uint64 (binary .LittleEndian .Uint32 (b [0x84 :0x88 ]))
205- modifyTimeExtra := uint64 (binary .LittleEndian .Uint32 (b [0x88 :0x8c ]))
206- createTimeExtra := uint64 (binary .LittleEndian .Uint32 (b [0x94 :0x98 ]))
207-
208- accessTimeHigh := accessTimeExtra & 0x3
209- changeTimeHigh := changeTimeExtra & 0x3
210- modifyTimeHigh := modifyTimeExtra & 0x3
211- createTimeHigh := createTimeExtra & 0x3
212-
213- accessTimeSeconds = (accessTimeHigh << 32 ) | accessTimeSeconds
214- changeTimeSeconds = (changeTimeHigh << 32 ) | changeTimeSeconds
215- modifyTimeSeconds = (modifyTimeHigh << 32 ) | modifyTimeSeconds
216- createTimeSeconds = (createTimeHigh << 32 ) | createTimeSeconds
217-
218- // now get the nanoseconds by using the upper 30 bites
219- accessTimeNanoseconds := accessTimeExtra >> 2
220- changeTimeNanoseconds := changeTimeExtra >> 2
221- modifyTimeNanoseconds := modifyTimeExtra >> 2
222- createTimeNanoseconds := createTimeExtra >> 2
198+ accessTimeSeconds := int32 (binary .LittleEndian .Uint32 (b [0x8 :0xc ]))
199+ changeTimeSeconds := int32 (binary .LittleEndian .Uint32 (b [0xc :0x10 ]))
200+ modifyTimeSeconds := int32 (binary .LittleEndian .Uint32 (b [0x10 :0x14 ]))
201+ createTimeSeconds := int32 (binary .LittleEndian .Uint32 (b [0x90 :0x94 ]))
202+
203+ accessTimeExtra := binary .LittleEndian .Uint32 (b [0x8c :0x90 ])
204+ changeTimeExtra := binary .LittleEndian .Uint32 (b [0x84 :0x88 ])
205+ modifyTimeExtra := binary .LittleEndian .Uint32 (b [0x88 :0x8c ])
206+ createTimeExtra := binary .LittleEndian .Uint32 (b [0x94 :0x98 ])
207+
208+ decodeTimestamp := func (seconds int32 , extra uint32 ) (int64 , int64 ) {
209+ // The formula derived from the kernel documentation table is:
210+ // Decoded = int64(int32(lower)) + (int64(extra_bits) << 32)
211+ sec := int64 (seconds ) + (int64 (extra & 0x3 ) << 32 )
212+ // Nanoseconds are in the upper 30 bits
213+ nano := int64 (extra >> 2 )
214+ return sec , nano
215+ }
216+
217+ atimeSec , atimeNano := decodeTimestamp (accessTimeSeconds , accessTimeExtra )
218+ ctimeSec , ctimeNano := decodeTimestamp (changeTimeSeconds , changeTimeExtra )
219+ mtimeSec , mtimeNano := decodeTimestamp (modifyTimeSeconds , modifyTimeExtra )
220+ crtimeSec , crtimeNano := decodeTimestamp (createTimeSeconds , createTimeExtra )
223221
224222 flagsNum := binary .LittleEndian .Uint32 (b [0x20 :0x24 ])
225223
@@ -287,10 +285,10 @@ func inodeFromBytes(b []byte, sb *superblock, number uint32) (*inode, error) {
287285 version : binary .LittleEndian .Uint64 (version ),
288286 inodeSize : binary .LittleEndian .Uint16 (b [0x80 :0x82 ]) + minInodeSize ,
289287 deletionTime : binary .LittleEndian .Uint32 (b [0x14 :0x18 ]),
290- accessTime : time .Unix (int64 ( accessTimeSeconds ), int64 ( accessTimeNanoseconds ) ),
291- changeTime : time .Unix (int64 ( changeTimeSeconds ), int64 ( changeTimeNanoseconds ) ),
292- modifyTime : time .Unix (int64 ( modifyTimeSeconds ), int64 ( modifyTimeNanoseconds ) ),
293- createTime : time .Unix (int64 ( createTimeSeconds ), int64 ( createTimeNanoseconds ) ),
288+ accessTime : time .Unix (atimeSec , atimeNano ),
289+ changeTime : time .Unix (ctimeSec , ctimeNano ),
290+ modifyTime : time .Unix (mtimeSec , mtimeNano ),
291+ createTime : time .Unix (crtimeSec , crtimeNano ),
294292 extendedAttributeBlock : binary .LittleEndian .Uint64 (extendedAttributeBlock ),
295293 project : binary .LittleEndian .Uint32 (b [0x9c :0x100 ]),
296294 extents : allExtents ,
@@ -332,17 +330,23 @@ func (i *inode) toBytes(sb *superblock) []byte {
332330 binary .LittleEndian .PutUint64 (version , i .version )
333331 binary .LittleEndian .PutUint64 (extendedAttributeBlock , i .extendedAttributeBlock )
334332
335- // there is some odd stuff that ext4 does with nanoseconds. We might need this in the future.
333+ // ext4 timestamps are 32 bits of seconds, plus an extra 32-bit field
334+ // containing 30 bits of nanoseconds and 2 bits of extended seconds.
336335 // See https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Timestamps
337- // binary.LittleEndian.PutUint32(accessTime[4:8], (i.accessTimeNanoseconds<<2)&accessTime[4])
338- binary .LittleEndian .PutUint64 (accessTime , uint64 (i .accessTime .Unix ()))
339- binary .LittleEndian .PutUint32 (accessTime [4 :8 ], uint32 (i .accessTime .Nanosecond ()))
340- binary .LittleEndian .PutUint64 (createTime , uint64 (i .createTime .Unix ()))
341- binary .LittleEndian .PutUint32 (createTime [4 :8 ], uint32 (i .createTime .Nanosecond ()))
342- binary .LittleEndian .PutUint64 (changeTime , uint64 (i .changeTime .Unix ()))
343- binary .LittleEndian .PutUint32 (changeTime [4 :8 ], uint32 (i .changeTime .Nanosecond ()))
344- binary .LittleEndian .PutUint64 (modifyTime , uint64 (i .modifyTime .Unix ()))
345- binary .LittleEndian .PutUint32 (modifyTime [4 :8 ], uint32 (i .modifyTime .Nanosecond ()))
336+ encodeAndWriteTimestamp := func (t time.Time , target []byte ) {
337+ seconds := t .Unix ()
338+ nanos := uint32 (t .Nanosecond ())
339+ high := uint32 ((seconds - int64 (int32 (seconds )))>> 32 ) & 0x3
340+ extra := (nanos << 2 ) | high
341+
342+ binary .LittleEndian .PutUint32 (target [0 :4 ], uint32 (seconds ))
343+ binary .LittleEndian .PutUint32 (target [4 :8 ], extra )
344+ }
345+
346+ encodeAndWriteTimestamp (i .accessTime , accessTime )
347+ encodeAndWriteTimestamp (i .createTime , createTime )
348+ encodeAndWriteTimestamp (i .changeTime , changeTime )
349+ encodeAndWriteTimestamp (i .modifyTime , modifyTime )
346350
347351 blocks := make ([]byte , 8 )
348352 binary .LittleEndian .PutUint64 (blocks , i .blocks )
0 commit comments