[Toybox] Stat %Z - What are valid values?

Rob Landley rob at landley.net
Wed Feb 8 13:05:13 PST 2017


I still have this todo item:

On 12/30/2016 11:28 AM, darken wrote:
> I've seen a value of "18446744072363093454" for stat %Z (seconds since
> epoch), for some files on a users device (Android 6.01).

To which Elliot replied with:

On 12/30/2016 01:39 PM, enh wrote:
> time_t on 32-bit Android is 32 bits.
> 
> that particular value looks like a sign-extension of 0xAFBEADCE, which
> is still some time in 2063. (so i'd assume this device's clock is set
> wrong, and i'd assume -- since this is presumably a 32-bit device with
> a signed 32-bit time_t -- that that's going to be causing other
> problems too.)

Then I said:

> Or if it's signed, that's -1346458162 which would be... sometime in the
> 1930's? hmmm... "./date -D %s -d -1346458162" is failing under glibc,
> and failing _differently_ under musl. (Wheee.)

At which point I got distracted going off on a tangent instead of just
using "touch -d".

Years ago Linus ruled ex cathedra that time_t is gonna stay signed on
Linux (because otherwise you can't represent times before Jan 1 1970,
which a lot of people's birthdays still are):

  https://lkml.org/lkml/2011/8/31/246

Which means a 32 bit time_t has the year 2038 problem (and x32 needs a
64 bit time_t to stay relevant).

The problem here _isn't_ about casting time_t to unsigned, because it
isn't an unsigned value. (And unsigned 64 bit value still couldn't
represent times before 1970: it has to _remain_ signed after being
promoted to 64 bits or it's broken.)

That's why I didn't apply Elliott's patch with the sizeof() and typecast
staircase: I don't see how it can be the proper fix to the reported problem:

> with 64-bit toybox:
> 
> angler:/ # date 060200002064

That date is past 2038...

> Mon Jun  2 00:00:00 GMT 2064
> angler:/ # rm /data/local/tmp/empty
> angler:/ # touch /data/local/tmp/empty
> angler:/ # ls -l /data/local/tmp/empty
> -rw-rw-rw- 1 root root 0 2064-06-02 00:00 /data/local/tmp/empty
> angler:/ # stat /data/local/tmp/empty
>   File: `/data/local/tmp/empty'
>   Size: 0 Blocks: 0 IO Blocks: 512 regular empty file
> Device: fd00h/64768d Inode: 3014659 Links: 1
> Access: (666/-rw-rw-rw-) Uid: (    0/    root) Gid: (    0/    root)
> Access: 2064-06-02 00:00:11.746667836
> Modify: 2064-06-02 00:00:11.746667836
> Change: 2064-06-02 00:00:11.746667836
> angler:/ # stat -c "%z %Z" /data/local/tmp/empty
> 2064-06-02 00:00:11.746667836 2979590411
> angler:/ # ^D

A 64 bit platform can represent that but a 32 bit one can't, because
it's past y2038.

> then with 32-bit toybox:
> 
> angler:/ # ls -l /data/local/tmp/empty
> -rw-rw-rw- 1 root root 0 1928-04-26 17:31 /data/local/tmp/empty

Because time_t is a 32 bit signed value there, so that bit pattern
represents a negative number.

> angler:/ # stat /data/local/tmp/empty
>   File: `/data/local/tmp/empty'
>   Size: 0 Blocks: 0 IO Blocks: 512 regular empty file
> Device: fd00h/64768d Inode: 3014659 Links: 1
> Access: (666/-rw-rw-rw-) Uid: (    0/    root) Gid: (    0/    root)
> Access: 1928-04-26 17:31:55.746667836
> Modify: 1928-04-26 17:31:55.746667836
> Change: 1928-04-26 17:31:55.746667836
> angler:/ # stat -c "%z %Z" /data/local/tmp/empty
> 1928-04-26 17:31:55.746667836 18446744072394174731

Why is "stat" showing the same data as "ls" a bad thing here? Your patch
to stat makes it diverge from ls? On a local i686-musl build:

/ # touch -d 1928-04-26T00:00:00 walrus
/ # ls -l walrus
-rw-r--r-- 1 root root 0 1928-04-26 00:00 walrus
/ # stat walrus
  File: `walrus'
  Size: 0	 Blocks: 0	 IO Blocks: 512	regular empty file
Device: 801h/2049d	 Inode: 14574425	 Links: 1
Access: (644/-rw-r--r--)   Uid: (    0/    root)   Gid: (    0/    root)
Access: 1928-04-26 00:00:00.000000000
Modify: 1928-04-26 00:00:00.000000000
Change: 2017-02-08 20:58:37.009291677
/ #

> two patches attached. one avoids sign extension for all calls to
> `out`, fixing %Z for systems with a signed 32-bit time_t.

What does this patch fix?

Rob


More information about the Toybox mailing list