otp
otp copied to clipboard
file:read_file_info fails on Windows with {error,badarg} for files on SMB share if last access time is not set
Describe the bug
file:read_file_info
fails on Windows (native) when called with a file on an SMB share, no matter if UNC path or mapped drive, if no last access time is set.
To Reproduce
Create a file from the client on an SMB share. Confirm in explorer that last access time is not set (displays as 00:00:00). This may require a Linux samba server instead of an actual Windows server. Then call file:read_file_info
on that file on the client. It should fail with {error,badarg}
.
Expected behavior
file:read_file_info
returns the file information, similar to this (WSL1 output):
{ok,{file_info,583,regular,read_write,
{{30828,9,14},{4,48,5}},
{{2022,10,10},{8,27,53}},
{{2022,10,10},{8,27,53}},
33279,1,21,0,6831742,0,0}}
Affected versions Found in OTP 25.1.
Additional context Erlang in WSL1 shows garbage for last access time (with a year in the 30000s), but doesn't fail.
Calling touch
on the file on the server "fixes" the issue, as it sets the last access time.
I think I have figured out what's happening:
- If last access time is not set, its value is 2^63-1.
- That, divided by TICKS_PER_SECOND==10000000, is 922337203685, subtract EPOCH_DIFFERENCE==11644473600 and you get 910692730085.
- In prim_file.erl:634, we call
adjust_time
withTimeType==local
, which callserlang:universaltime_to_localtime(erlang:posixtime_to_universaltime(910692730085))
-
erlang:posixtime_to_universaltime(910692730085)=={{30828,9,14},{2,48,5}}
, but on native Windows,erlang:universaltime_to_localtime({{30828,9,14},{2,48,5}})
fails with
** exception error: bad argument
in function erlang:posixtime_to_universaltime/1
called as erlang:posixtime_to_universaltime({{30828,9,14},{2,48,5}})
*** argument 1: not an integer
- The cause (I think) for that is that
{{30828,9,14},{2,48,5}}
is not a valid SYSTEMTIME, which ends in 30827, sosys_localtime_r
fails. (On Linux and other Unix-like OSs, we just call localtime_r, which doesn't have that problem.)
I haven't localized the exact place where it fails, because in the end, this is just a case of "garbage in, garbage out". If there is no valid data in the last-access-time field, we should return nothing there or any arbitrary, unproblematic value (say {{9999,12,31},{23,59,59}}
).
Side note: Who reads the last access time anyway – especially on Windows, where it's usually disabled?
Thanks for your report, and sorry for the late reply. I got back from long-term leave late last week and didn't manage to fix this in time for the upcoming OTP 25.2
patch. I'll make a PR with the fix as soon as that is released.
I've merged a fix into maint
now, which will be released as 25.3
early next year. Thanks again for your report!