[Android General] k1ll3r8e:
Heyho,

THX for that info, i'll check the "adbd" source which LOS uses, maybe there is the prob. According to "adb pull -a" i'll also have a look at the adb source, because i think they do some "touch" stuff. Because the ADB-Protocol it self only supports creation/last modified time. In the source is a another "struct" for "STA2" (stat 2) command. But i have never seen a adb binary which supports this. (All binaries use the "STAT" command.)

EDIT 1:

Just checked the adb source again, seems they changed it a bit...

(This is the current STAT (v1) header)

# cmd name STAT or STA2 // 4 bytes
st->st_mode = msg.stat_v1.mode; // 4 bytes
st->st_size = msg.stat_v1.size; // 4 bytes
st->st_ctime = msg.stat_v1.mtime; // 4 bytes
st->st_mtime = msg.stat_v1.mtime; // 4 bytes

My HTC-One M9, Sensation, VM-Ware (Kitkat - Nougat) none of them has a 20 byte header. ALL of them return a 16 byte header.

CMD // 4 bytes
Mode // 4 bytes
Size // 4 bytes
CTime // 4 bytes

So it seems the protocol is highly inconsistent... I'll check how much time gets lost by calling touch on each file, because, currently i open a sync channel via an smart-socket, transfer the file and read all data provided by the protocol header. This is really fast, but if i have to spin up each time another channel to get a shell for the touch, this will increase the time each copy needs. Because, a shell depending on the version (v1, v2), has a lot checks you need to perform, specially the shell_v2 because it's like a ssh protocol.

EDIT 2:

Just for completeness, i'm pretty sure your device also sends only a 16 byte header for the stat v1 command, because:

(This is a cut of my implemented "Stat(byte[] bytes)" class)

if (c == (uint)SyncCmd.STA2 && bytes.Length >= 72)
{
ID = SyncCmd.STA2;
Error = bytes.GetUInt32LE(4);
Dev = bytes.GetUInt64LE(8);
INode = bytes.GetUInt64LE(16);
Mode = bytes.GetUInt32LE(24);
NLink = bytes.GetUInt32LE(28);
UID = bytes.GetUInt32LE(32);
GID = bytes.GetUInt32LE(36);
Size = bytes.GetUInt64LE(40);
ATime = bytes.GetInt64LE(48);
MTime = bytes.GetInt64LE(56);
CTime = bytes.GetInt64LE(64);
}
else if (c == (uint)SyncCmd.STAT && bytes.Length == 16)
{
ID = SyncCmd.STAT;
Mode = bytes.GetUInt32LE(4);
Size = bytes.GetUInt32LE(8);
CTime = bytes.GetUInt32LE(12);
}

As you can see, the both structures differ in there field order, if your device would send a 20 byte header, the test (bytes.Length == 16) wouldn't match. And you couldn't download a file. ;)

EDIT 3:

After playing a while with "stat" and "touch" on some Android versions, i decided to rely on those functions. The next build should restore and write the correct timestamps.

EDIT 4:

Well, setting timestamps on the SD-Card doesn't work, also, setting timestamps on the "internal" SD-Card doesn't work either. Seems that it's related to the underlying FS. If i try to set the timestamp on an ext4 partition, it works. So it doesn't make sense to rewrite the push/pull functions because the return of touch for 99% of the time will be "touch: '/sdcard/TWRP/test.pdf': Operation not permitted". So it's simply a time waste during the copy procedure. BUT, i'll implement it at least for the download, so u'll get the correct timestamps on Windows.

EDIT 5:

Added a screenshot of the new "Properties Window" which also proves that the download timestamps are now correct.

(Btw. C doesn't mean created - it means changed)

stat /sdcard
File: `/sdcard' -> `/storage/self/primary'
Size: 21	Blocks: 0	IO Blocks: 512	symbolic link
Device: 1h/1d	Inode: 4432	Links: 1
Access: (777/lrwxrwxrwx)	Uid: ( 0/ root)	Gid: ( 0/ root)
Access: 1970-01-01 01:00:00.000000000
Modify: 1970-01-01 01:00:00.000000000
Change: 1970-01-01 01:00:00.360063176

Little update about the "creation time". After a bit research i found this post on Stack Exchange, there is explained that the so called "birth time" is stored since ext4 as part of the INode field. But it seems you need a special version of "stat" to read this info, it's called "statx". But so far i could see, Android doesn't support this feature, maybe some kernel does but it seems that it's more the rare case.

Regards,

Sebastian