Bug 40368

Summary: Setting FileInfo.LastWriteTime has different results with mono32 and mono64
Product: [Mono] Runtime Reporter: Ankit Jain <ankit.jain>
Component: io-layerAssignee: Rodrigo Kumpera <kumpera>
Status: RESOLVED FIXED    
Severity: normal CC: masafa, mono-bugs+mono, mono-bugs+runtime, till.lorentzen, vargaz
Priority: ---    
Version: unspecified   
Target Milestone: ---   
Hardware: PC   
OS: Mac OS   
Tags: Is this bug a regression?: ---
Last known good build:

Description Ankit Jain 2016-04-13 22:51:05 UTC
Setting the LastWriteTime for a file via FileInfo:

var info = new FileInfo(file);
var time = new DateTime(2039, 1, 1);
info.LastWriteTime = time;

// reading that time again
info = new FileInfo(file);

// with mono32: info.LastWriteTime: 25-11-1902 17:31:44
// ls -l <file> : Nov 25  1902 /var/folders/3g/27cm3t29301gds8d89pf3xyh0000gp/T/tmp4f9ed2dc.tmp

// with mono64: info.LastWriteTime: 01-01-2039 00:00:00
// ls -l <file> : Jan  1  2039 /var/folders/3g/27cm3t29301gds8d89pf3xyh0000gp/T/tmp3969d9af.tmp

// expected:    info.LastWriteTime: 01-01-2039 00:00:00

It works fine with a "32bit date".

Mono JIT compiler version 4.4.0 (mono-4.4.0-branch/a3fabf1 Fri Apr  8 13:48:29 EDT 2016)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
        TLS:           normal
        SIGSEGV:       altstack
        Notification:  kqueue
        Architecture:  x86
        Disabled:      none
        Misc:          softdebug
        LLVM:          yes(3.6.0svn-mono-master/a173357)
        GC:            sgen

Test program:

using System;
using System.IO;

public class Test
{
        public static void Main ()
        {
                string file = Path.GetTempFileName();
                File.WriteAllText(file, String.Empty);
                Console.WriteLine ($"file: {file}");

                var info = new FileInfo(file);
                Console.WriteLine ($"LastWriteTime: {info.LastWriteTime}");

                var time = new DateTime(2039, 1, 1);
                Console.WriteLine ($"Setting LastWriteTime to {time}");
                info.LastWriteTime = time;

                info = new FileInfo(file);
                Console.WriteLine ($"\tReading with a new instance of FileInfo: info.LastWriteTime: {info.LastWriteTime}, expected to be {time}");
        }
}
Comment 1 Marek Safar 2016-04-14 20:13:35 UTC
This is Mono Year 2038 problem

I/O layer uses wrongly `utimbuf` at https://github.com/mono/mono/blob/255ce320b0da31b6e50cef084a4079039ccb39d6/mono/io-layer/io-portability.c#L117 which is CPU specific in the way that it uses time_t which can be 32-bit only.

I'll leave it to runtime team to decide what's the best fix for this to be CPU agnostic.
Comment 2 Zoltan Varga 2016-04-15 00:28:14 UTC
There is no posix api to set the file times to later that 2038. We can throw an exception instead.
Comment 3 Marek Safar 2016-04-15 07:00:42 UTC
Possibly if there easy way to detect time_t is 32bit, e.g. OpenBSD uses 64bits on 32bits system and some new stuff uses float/double.

Or do what glibc does and have _TIME_BITS=64

Or use something like

https://github.com/evalEmpire/y2038
Comment 4 Rodrigo Kumpera 2016-04-15 22:33:12 UTC
Working on it.
Comment 5 Marek Safar 2016-04-16 07:46:50 UTC
*** Bug 23934 has been marked as a duplicate of this bug. ***
Comment 6 Rodrigo Kumpera 2016-04-19 00:09:04 UTC
Fixed in 7b4a585094187d087c2dd7e55740933663485c84.