Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SetCreationTime on Mac #39132

Closed
hamarb123 opened this issue Jul 11, 2020 · 54 comments · Fixed by #49555
Closed

SetCreationTime on Mac #39132

hamarb123 opened this issue Jul 11, 2020 · 54 comments · Fixed by #49555
Assignees
Labels
Milestone

Comments

@hamarb123
Copy link
Contributor

hamarb123 commented Jul 11, 2020

Description

The method System.IO.File.SetCreationTime[Utc](string, DateTime) does not work correctly on mac, but the System.IO.File.GetCreationTime[Utc](string, DateTime) does.
The following code snippet creates different results on mac and windows:

using System.IO;

static class Program
{
  static void Main()
  {
    string filePath = @"/path/to/file"; //change to appropriate path where file doesn't exist
    File.Create(filePath);
    FileInfo fi = new FileInfo(filePath);
    fi.LastAccessTimeUtc = new DateTime(2020, 1, 2);
    fi.LastWriteTimeUtc = new DateTime(2020, 1, 3);
    fi.CreationTimeUtc = new DateTime(2020, 1, 1);
    fi.Refresh();
    Console.WriteLine(fi.LastAccessTimeUtc.ToString()); //expect 2/1/2020 12:00:00 am
    Console.WriteLine(fi.LastWriteTimeUtc.ToString()); //expect 3/1/2020 12:00:00 am, get 1/1/2020 12:00:00 am on Mac
    Console.WriteLine(fi.CreationTimeUtc.ToString()); //expect 1/1/2020 12:00:00 am
  }
}

I believe that this method contains the implementation for Unix platforms, but I think that Mac should have a different implementation for this function to Unix as there is an actual way to do this on Mac.

Swift code to change date:

let filePath = "/path/to/file"
let date = NSDate()
let fileAttributes = [FileAttributeKey.creationDate: date]
FileManager.default.setAttributes(fileAttributes, ofItemAtPath: filePath)

This code, in theory, sets the creation date of the file; there must be a way to implement this in C# on the Mac version, it is also probably a good idea to implement the other methods (last write and access dates) like this, as it seems that setting the last write date changes the creation date sometimes (see this).

Configuration

I tested the code on macOS Catalina (x64) and Windows 10 (x64). It is specific to unix platforms.

Regression?

I do not know.

Other information

A workaround could be to set the creation date, and then set the modification date back again. This will work sometimes, but not always.

@Dotnet-GitSync-Bot
Copy link
Collaborator

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label Jul 11, 2020
@danmoseley
Copy link
Member

We'd certainly like to make it work if there's an API. Can you figure out what API we could call? I assume there's something lower level.

@danmoseley danmoseley added this to the Future milestone Jul 12, 2020
@hamarb123
Copy link
Contributor Author

We'd certainly like to make it work if there's an API. Can you figure out what API we could call? I assume there's something lower level.

@danmosemsft It took me a while, but I have figured out working C# code that does what it should:

using System;
using System.Runtime.InteropServices;

namespace dotnet_runtime_39132_poc
{
	class Program
	{
		internal const string libobjc = "/usr/lib/libobjc.dylib";

		[DllImport(libobjc)]
		private static extern IntPtr objc_getClass(string className);

		[DllImport(libobjc)]
		private static extern IntPtr sel_registerName(string str);

		[DllImport(libobjc)]
		private static extern IntPtr objc_msgSend(IntPtr basePtr, IntPtr selector);

		[DllImport(libobjc)]
		private static extern IntPtr objc_msgSend(IntPtr basePtr, IntPtr selector, double secondsSince);

		[DllImport(libobjc)]
		private static extern IntPtr objc_msgSend(IntPtr basePtr, IntPtr selector, [MarshalAs(UnmanagedType.LPUTF8Str)] string arg1);

		[DllImport(libobjc)]
		private static extern IntPtr objc_msgSend(IntPtr basePtr, IntPtr selector, IntPtr arg1, IntPtr arg2);

		[DllImport(libobjc)]
		private static extern sbyte objc_msgSend(IntPtr basePtr, IntPtr selector, IntPtr arg1, IntPtr arg2, IntPtr arg3);

		static void Main(string[] args)
		{
			SetTime("/Users/Hamish/Desktop/test file", true, new DateTime(2020, 1, 1, 10, 0, 57));
			SetTime("/Users/Hamish/Desktop/test file", false, new DateTime(2020, 1, 2, 10, 0, 57));
		}

		static IntPtr NSDate;
		static IntPtr NSDictionary;
		static IntPtr NSFileManager;
		static IntPtr NSString;
		static IntPtr alloc;
		static IntPtr init;
		static IntPtr initWithUTF8String_;
		static IntPtr initWithTimeIntervalSince1970_;
		static IntPtr dictionaryWithObject_forKey_;
		static IntPtr defaultManager;
		static IntPtr setAttributes_ofItemAtPath_error_;
		static IntPtr release;
		static IntPtr NSFileCreationDate;
		static IntPtr NSFileModificationDate;
		static IntPtr _NSFileManager;

		static Program()
		{
			NSDate = objc_getClass("NSDate");
			NSDictionary = objc_getClass("NSDictionary");
			NSFileManager = objc_getClass("NSFileManager");
			NSString = objc_getClass("NSString");

			alloc = sel_registerName("alloc");
			init = sel_registerName("init");
			initWithUTF8String_ = sel_registerName("initWithUTF8String:");
			initWithTimeIntervalSince1970_ = sel_registerName("initWithTimeIntervalSince1970:");
			dictionaryWithObject_forKey_ = sel_registerName("dictionaryWithObject:forKey:");
			defaultManager = sel_registerName("defaultManager");
			setAttributes_ofItemAtPath_error_ = sel_registerName("setAttributes:ofItemAtPath:error:");
			release = sel_registerName("release");

			NSFileCreationDate = objc_msgSend(NSString, alloc);
			NSFileCreationDate = objc_msgSend(NSFileCreationDate, initWithUTF8String_, "NSFileCreationDate");

			NSFileModificationDate = objc_msgSend(NSString, alloc);
			NSFileModificationDate = objc_msgSend(NSFileModificationDate, initWithUTF8String_, "NSFileModificationDate");

			_NSFileManager = objc_msgSend(NSFileManager, defaultManager);
		}

		static void SetTime(string path, bool isModificationDate, DateTime time)
		{
			var date = objc_msgSend(NSDate, alloc);
			date = objc_msgSend(date, initWithTimeIntervalSince1970_, (time.ToUniversalTime() - DateTime.UnixEpoch).TotalSeconds);
			var fileAttributes = objc_msgSend(NSDictionary, dictionaryWithObject_forKey_, date, isModificationDate ? NSFileModificationDate : NSFileCreationDate);
			var native_filePath = objc_msgSend(NSString, alloc);
			native_filePath = objc_msgSend(native_filePath, initWithUTF8String_, path);
			var retV = objc_msgSend(_NSFileManager, setAttributes_ofItemAtPath_error_, fileAttributes, native_filePath, IntPtr.Zero);
			objc_msgSend(date, release);
			objc_msgSend(fileAttributes, release);
			objc_msgSend(native_filePath, release);
		}
	}
}

This code can set the creation date, and the modification date.
There is one caveat: if you set the modification date to before the creation date it will change the creation date to the new modification date, which differs in behaviour to Windows. This could easily happen when you are copying file (the modification date stays, but the creation date changes to the current date). So I recommend that we check the creation date when changing the modification date, and changing the creation date back afterwards if it was after the new modification date, which would look something like this:

var creationDate = File.GetCreationTimeUtc(path);
SetTime(path, true, newModDateUtc);
if (newModDateUtc < creationDate) SetTime(path, false, creationDate);

Would this be an acceptable way to implement this? If so I'll create a PR with the necessary changes (I'll need to know how to make this code Mac only w/o using #ifs if that's required).

@danmoseley
Copy link
Member

danmoseley commented Jul 13, 2020

Area owners for IO should answer whether they'd accept a PR. (@carlossanlop @jozkee)

Most IO stuff is done with glibc calls - but we do have some libobjc use elsewhere: https://github.com/dotnet/runtime/blob/master/src/libraries/Common/src/Interop/OSX/Interop.libobjc.cs

https://github.com/dotnet/runtime/blob/master/src/libraries/System.IO.FileSystem/src/System/IO/FileStatus.Unix.cs would have to be split into ...OSX.cs and OtherUnix.cs and System.IO.FileSystem.dll looks like it only has a Unix configuration today, it would need to have an OSX configuration broken out.

@hamarb123
Copy link
Contributor Author

@carlossanlop @jozkee, would you guys accept a PR for this?

@jozkee
Copy link
Member

jozkee commented Jul 13, 2020

FWIW: This also fails on linux distros, I tried it on WSL and got the reported error so maybe we don't have to split the file and perhaps there is an unified way to solve the problem for Unix (Linux and OSX).

@hamarb123
Copy link
Contributor Author

FWIW: This also fails on linux distros, I tried it on WSL and got the reported error so maybe we don't have to split the file and perhaps there is an unified way to solve the problem for Unix (Linux and OSX).

@jozkee I do not believe that there is an easy way to do it on all Unix systems. It says that there is no API to update the CreationTime on Unix systems here, and it says that Linux does not even store it, so I think that we should either have it as a known issue on Linux (and document it, as it took me quite a while to debug my code when it was undocumented), or throw a PlatformNotSupportedException when trying to set the creation date on Linux platforms.

@hamarb123
Copy link
Contributor Author

But there could be an API that I do not know about.

@danmoseley
Copy link
Member

From what I have read recently and in the past, there is not really a way to do this on Linux. And that is why the Apple way is not using a POSIX API at all.

@jozkee
Copy link
Member

jozkee commented Jul 13, 2020

It says that there is no API to update the CreationTime on Unix systems here

Ah, I didn't see that part.

OK, in that case I think is good that we could fix this for Mac, @hamarb123 a PR for it would be very welcome.

@hamarb123
Copy link
Contributor Author

hamarb123 commented Jul 14, 2020

@jozkee what TFMs should I break it up into? The current csproj file has:

<TargetFrameworks>$(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser</TargetFrameworks>

@hamarb123
Copy link
Contributor Author

@danmosemsft @jozkee I have a few questions.
What sort of exception should I throw here?
Should I keep the comments on these lines?
Did I set up the project files correctly?
I do not appear to be able to run the tests locally. Log:

Hamish@Hamish-Macbook runtimeNew % ./build.sh -subset libs.tests -test -c Release
__DistroRid: osx-x64
__RuntimeId: osx-x64
  Determining projects to restore...
  Tool 'coverlet.console' (version '1.7.2') was restored. Available commands: coverlet
  Tool 'dotnet-reportgenerator-globaltool' (version '4.5.8') was restored. Available commands: reportgenerator
  Tool 'microsoft.dotnet.xharness.cli' (version '1.0.0-prerelease.20352.2') was restored. Available commands: xharness
  
  Restore was successful.
  All projects are up-to-date for restore.
  Determining projects to restore...
/Users/Hamish/Desktop/runtimeNew/Build.proj : error NU1102: Unable to find package microsoft.private.intellisense with version (= 3.0.0-preview-20200715.1)
/Users/Hamish/Desktop/runtimeNew/Build.proj : error NU1102:   - Found 15 version(s) in dotnet5-transport [ Nearest version: 3.1.0-preview-20191225.2 ]
/Users/Hamish/Desktop/runtimeNew/Build.proj : error NU1102:   - Found 2 version(s) in nuget.org [ Nearest version: 1.0.0-rc3-24214-00 ]
/Users/Hamish/Desktop/runtimeNew/Build.proj : error NU1102:   - Found 1 version(s) in dotnet-eng [ Nearest version: 3.0.0-preview8-190815-0 ]
/Users/Hamish/Desktop/runtimeNew/Build.proj : error NU1102:   - Found 1 version(s) in dotnet-tools [ Nearest version: 3.0.0-preview8-190815-0 ]
/Users/Hamish/Desktop/runtimeNew/Build.proj : error NU1102:   - Found 0 version(s) in dotnet5
  Failed to restore /Users/Hamish/Desktop/runtimeNew/Build.proj (in 6.26 sec).
  321 of 322 projects are up-to-date for restore.

Build FAILED.

/Users/Hamish/Desktop/runtimeNew/Build.proj : error NU1102: Unable to find package microsoft.private.intellisense with version (= 3.0.0-preview-20200715.1)
/Users/Hamish/Desktop/runtimeNew/Build.proj : error NU1102:   - Found 15 version(s) in dotnet5-transport [ Nearest version: 3.1.0-preview-20191225.2 ]
/Users/Hamish/Desktop/runtimeNew/Build.proj : error NU1102:   - Found 2 version(s) in nuget.org [ Nearest version: 1.0.0-rc3-24214-00 ]
/Users/Hamish/Desktop/runtimeNew/Build.proj : error NU1102:   - Found 1 version(s) in dotnet-eng [ Nearest version: 3.0.0-preview8-190815-0 ]
/Users/Hamish/Desktop/runtimeNew/Build.proj : error NU1102:   - Found 1 version(s) in dotnet-tools [ Nearest version: 3.0.0-preview8-190815-0 ]
/Users/Hamish/Desktop/runtimeNew/Build.proj : error NU1102:   - Found 0 version(s) in dotnet5
    0 Warning(s)
    1 Error(s)

Time Elapsed 00:00:14.17
Build failed (exit code '1').

@danmoseley
Copy link
Member

danmoseley commented Jul 21, 2020

@jozkee's area but my guesses

  1. IOException seems fine, but string needs to be in the resources
  2. The SetCreationOrModificationTimeOfFileInternal method probably shouldn't be in the Interop file but instead in FileStatus.OSX.cs. Those files are generally just extern declarations, enums etc. There is sometimes a little implementation there eg when it's really necessary to use the API correctly, in which case the extern is private. It's not entirely consistent.
  3. Nit: you'll want to check against the style guide/existing code style before throwing up the PR, eg., spaces between the extern declarations, one space after // etc.
  4. Does it matter if macOS sets creation time after modification time? Maybe we should just let it do its natural thing rather than working around it? We prefer to expose OS'es in their "natural state" only trying to align behaviors when it's necessary to make the API work according to its promise. I think setting modification time is not a promise to fix up creation time.?
  5. Why did you need to repeat files like Interop.ChMod.cs in the project? Those should be pulled in for macOS just because it's Unix. Should be possible for the project file edits to be quite small.
  6. I think by exploding Unix in the configurations, we may need to include Android, iOS and tvOS. But, one would hope they could map to Linux and macOS/OSX respectively. This can be figured out when you have a PR up.
  7. Some of the vars that just wrap strings might be clearer if they were just directly in the method call. Eg., see GetOperatingSystemVersion() where we have objc_getClass("NSProcessInfo") etc inline.

@danmoseley
Copy link
Member

Should I keep the comments on these lines?

I don't think so since a code search finds the callers.

Unfortunately I don't know the answer for the build failure. Bad sync point perhaps? Maybe git clean -fdx and git pull forward and try again.

@jozkee
Copy link
Member

jozkee commented Jul 21, 2020

Maybe git clean -fdx and git pull forward and try again.

@hamarb123 are you able to perform ./build.sh without any switch or that also fails?

Perhaps you may want to take a look at https://github.com/dotnet/runtime/blob/master/docs/workflow/README.md#workflow-guide and once your build suceeds you can go into the folder of one of the test projects and run it individually with dotnet msbuild /t:test

@hamarb123
Copy link
Contributor Author

Sorry, I haven't had a chance to work on this for a while, and probably won't for a while to come either.
I'll leave my fork there for anyone else wanting to work on it.
re Dan's Q4,
as I said previously

There is one caveat: if you set the modification date to before the creation date it will change the creation date to the new modification date, which differs in behaviour to Windows. This could easily happen when you are copying file (the modification date stays, but the creation date changes to the current date). So I recommend that we check the creation date when changing the modification date, and changing the creation date back afterwards if it was after the new modification date, which would look something like this:

var creationDate = File.GetCreationTimeUtc(path);
SetTime(path, true, newModDateUtc);
if (newModDateUtc < creationDate) SetTime(path, false, creationDate);

And it makes sense that it should set only the modification date (to me) when you set the modification date, otherwise I think we should have a note in the docs saying the current behaviour on Mac.

@marek-safar marek-safar added the os-mac-os-x macOS aka OSX label Aug 2, 2020
@danmoseley
Copy link
Member

OK, thanks for the effort @hamarb123 i will close this until you or someone wishes to take it further.

@ghost ghost locked as resolved and limited conversation to collaborators Dec 8, 2020
@carlossanlop
Copy link
Member

carlossanlop commented Mar 11, 2021

Reopening this issue. @hamarb123 wrote:

I found a method to make it work that doesn't use obj c apis as I was having issues with setting the attribute on symbolic links in my project using the obj c method, here's the api: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setattrlist.2.html.
I've used this code in my own project for a while now and it seems to work completely fine and I haven't had any issues with it.
I'm happy to share the code as a part of a PR.
It also doesn't require the workaround for setting the modification date to before the creation date that the old code needed from #39132. You can also theoretically set the access time using ATTR_CMN_ACCTIME with this api, but I've not found any use in doing so in my code, so I didn't bother to implement it, and there was no issues with the current implementation of set last access time AFAIK on mac.
I'd be happy to attempt making a PR if @carlossanlop and/or @jozkee are alright with it.
Also, I'm not sure if it'd work on an M1 mac as I do not have one, but I see no reason why it wouldn't.

@hamarb123 feel free to send a PR, I'm looking forward to reviewing it.

@carlossanlop carlossanlop reopened this Mar 11, 2021
@carlossanlop carlossanlop removed the untriaged New issue has not been triaged by the area owner label Mar 11, 2021
@safern
Copy link
Member

safern commented Mar 15, 2021

@hamarb123
Copy link
Contributor Author

hamarb123 commented Mar 15, 2021

I've got them all, the only thing I can think of is that my XCode version is 12.3 instead of 12.4, does this matter?
Also, I think the actual error is around here:

  [  3%] Building C object Native.Unix/System.Security.Cryptography.Native.Apple/CMakeFiles/System.Security.Cryptography.Native.Apple-Static.dir/pal_random.c.o
  [  3%] Building C object Native.Unix/System.IO.Compression.Native/CMakeFiles/System.IO.Compression.Native-Static.dir/Users/Hamish/Projects/Clones/runtime/src/libraries/Native/AnyOS/brotli/dec/huffman.c.o
  [  3%] Building C object pal/src/libunwind/src/CMakeFiles/libunwind_dac.dir/mi/Gget_reg.c.o
  [  3%] Building C object Native.Unix/System.Globalization.Native/CMakeFiles/System.Globalization.Native-Static.dir/pal_normalization.c.o
  [  3%] Building C object Native.Unix/System.Security.Cryptography.Native.Apple/CMakeFiles/System.Security.Cryptography.Native.Apple-Static.dir/pal_rsa.c.o
  Unknown action: -c
  make[2]: *** [hosts/unixcorerun/corerun] Error 255
  make[2]: *** Deleting file `hosts/unixcorerun/corerun'
  make[1]: *** [hosts/unixcorerun/CMakeFiles/corerun.dir/all] Error 2
  make[1]: *** Waiting for unfinished jobs....
  [  3%] Building C object Native.Unix/System.Native/CMakeFiles/System.Native-Static.dir/pal_networkstatistics.c.o
  [  3%] Building C object pal/src/libunwind/src/CMakeFiles/libunwind_dac.dir/mi/Gset_reg.c.o

@danmoseley
Copy link
Member

@AaronRobinsonMSFT is this related to your corerun change?

@danmoseley
Copy link
Member

Oh - since that's not merged yet - no!

@safern
Copy link
Member

safern commented Mar 15, 2021

@hamarb123 it would be helpful if you could share compile-commands.json file under artifacts/obj/*.

@hamarb123
Copy link
Contributor Author

Hi @safern, I don't seem to have any files named compile-commands.json in the whole runtime folder, or anything (that I can see) named similarly in the artifacts/obj/* folder.

@safern
Copy link
Member

safern commented Mar 16, 2021

Hmmm... could you try adding this to src/coreclr/CMakeLists.txt so that it generates that file?

set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "")

Also, it might be helpful if you could share the version of cmake that you have? i.e running cmake --version.

@hamarb123
Copy link
Contributor Author

cmake version 3.19.1
CMake suite maintained and supported by Kitware (kitware.com/cmake).
It was installed by homebrew (can tell by location of executable).
With addition to CMakeLists: compile_commands.json.zip!

@hoyosjs
Copy link
Member

hoyosjs commented Mar 17, 2021

Oddly enough, it builds on all machines and SDK's that I've tried. Even the command verbatim from your compile command list. Can you please try this:

pushd /Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release
VERBOSE=1 make corerun
popd

@danmoseley
Copy link
Member

my XCode version is 12.3 instead of 12.4, does this matter?

I have no idea, but would it make sense to update it?

@hoyosjs
Copy link
Member

hoyosjs commented Mar 17, 2021

For what is worth, I tried both 12.1 and 12.4 and CMake 3.16.5 and 3.19.7. For SDK I used macOS SDK 10.15 instead of 11.1 as you used, and so did @safern. Trying to update the SDK to test that out.

@hamarb123
Copy link
Contributor Author

hamarb123 commented Mar 17, 2021

@hoyosjs thanks for your command, I think it's found the issue.
Output:

Hamish@Hamish-Macbook runtime % pushd /Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release
~/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release ~/Projects/Clones/runtime
Hamish@Hamish-Macbook OSX.x64.Release % VERBOSE=1 make corerun
/usr/local/Cellar/cmake/3.19.1/bin/cmake -S/Users/Hamish/Projects/Clones/runtime/src/coreclr -B/Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release --check-build-system CMakeFiles/Makefile.cmake 0
Re-run cmake file: Makefile older than: /Users/Hamish/Projects/Clones/runtime/src/coreclr/CMakeLists.txt
Detected OSX x86_64
PGO data file NOT found: /data/clrjit.profdata
PGO data file NOT found: /data/coreclr.profdata
-- Configuring done
CMake Warning (dev):
  Policy CMP0068 is not set: RPATH settings on macOS do not affect
  install_name.  Run "cmake --help-policy CMP0068" for policy details.  Use
  the cmake_policy command to set the policy and suppress this warning.

  For compatibility with older versions of CMake, the install_name fields for
  the following targets are still affected by RPATH settings:

   mscordbi

This warning is for project developers.  Use -Wno-dev to suppress it.

-- Generating done
-- Build files have been written to: /Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release
/Applications/Xcode.app/Contents/Developer/usr/bin/make  -f CMakeFiles/Makefile2 corerun
/usr/local/Cellar/cmake/3.19.1/bin/cmake -S/Users/Hamish/Projects/Clones/runtime/src/coreclr -B/Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release --check-build-system CMakeFiles/Makefile.cmake 0
/usr/local/Cellar/cmake/3.19.1/bin/cmake -E cmake_progress_start /Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release/CMakeFiles 0
/Applications/Xcode.app/Contents/Developer/usr/bin/make  -f CMakeFiles/Makefile2 hosts/unixcorerun/CMakeFiles/corerun.dir/all
/Applications/Xcode.app/Contents/Developer/usr/bin/make  -f hosts/unixcorerun/CMakeFiles/corerun.dir/build.make hosts/unixcorerun/CMakeFiles/corerun.dir/depend
cd /Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release && /usr/local/Cellar/cmake/3.19.1/bin/cmake -E cmake_depends "Unix Makefiles" /Users/Hamish/Projects/Clones/runtime/src/coreclr /Users/Hamish/Projects/Clones/runtime/src/coreclr/hosts/unixcorerun /Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release /Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release/hosts/unixcorerun /Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release/hosts/unixcorerun/CMakeFiles/corerun.dir/DependInfo.cmake --color=
/Applications/Xcode.app/Contents/Developer/usr/bin/make  -f hosts/unixcorerun/CMakeFiles/corerun.dir/build.make hosts/unixcorerun/CMakeFiles/corerun.dir/build
Linking CXX executable corerun
cd /Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release/hosts/unixcorerun && /usr/local/Cellar/cmake/3.19.1/bin/cmake -E cmake_link_script CMakeFiles/corerun.dir/link.txt --verbose=1
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -O3 -DNDEBUG -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk -mmacosx-version-min=10.15 -Wl,-search_paths_first -Wl,-headerpad_max_install_names  -mmacosx-version-min=10.13 CMakeFiles/corerun.dir/corerun.cpp.o CMakeFiles/corerun.dir/__/__/version.c.o -o corerun  -lpthread 
cd /Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release/hosts/unixcorerun && /usr/local/bin/paxctl -c -m /Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/OSX.x64.Release/hosts/unixcorerun/corerun
Unknown action: -c
make[3]: *** [hosts/unixcorerun/corerun] Error 255
make[3]: *** Deleting file `hosts/unixcorerun/corerun'
make[2]: *** [hosts/unixcorerun/CMakeFiles/corerun.dir/all] Error 2
make[1]: *** [hosts/unixcorerun/CMakeFiles/corerun.dir/rule] Error 2
make: *** [corerun] Error 2

I'm not sure where paxctl is supposed to be coming from, but it's coming from Parallels.
Do you know where the original paxctl is, or is it not supposed to be there on macOS?
My paxctl was at /usr/local/bin/paxctl which linked to /Applications/Parallels Access.app/Contents/MacOS/paxctl

@danmoseley
Copy link
Member

My guess is that it's a completely different tool that happens to have the same name (something like 'parallels access' vs 'page access'). The command line here: https://kb.parallels.com/en/121134 does not look like the command line for the expected tool: http://man.he.net/man1/paxctl

My guess is that this isn't expected to be found on macOS. @janvorli can you confirm?

@danmoseley
Copy link
Member

and if so, should it be wrapped with

if (CLR_CMAKE_TARGET_LINUX)
...
endif()

or something else?

@hoyosjs
Copy link
Member

hoyosjs commented Mar 17, 2021

Yes, as Dan says this is a collision in tool names. I believe only Linux supports paxctl as macOS uses other mechanisms for page protection, so it would just be wrapping the implementation of the function that's in

if (NOT PAXCTL STREQUAL "PAXCTL-NOTFOUND")

In a if (CLR_CMAKE_HOST_LINUX) ... endif(). You can try that locally to get yourself unstuck @hamarb123 while we go through the PR process. @danmoseley currently @janvorli is out of the office for another week. I'll make the PR to address this tomorrow.

@hamarb123
Copy link
Contributor Author

hamarb123 commented Mar 17, 2021

@hoyosjs thank you!
It seems like its building now.
Here's the changes I have locally

I've still got the following issue, but I believe it can be fixed by adding the ilasm/ildasm executable to the full disk access list.

  /var/folders/bl/34cy8fs17fg5f8c7j3f2hxfc0000gp/T/tmpfadd7434568b4cbe9fb32c694cce9a05.exec.cmd: line 2: /Users/Hamish/.nuget/packages/runtime.osx-x64.microsoft.netcore.ilasm/6.0.0-preview.3.21157.6/runtimes/osx-x64/native/ilasm: Permission denied
/Users/Hamish/.nuget/packages/microsoft.net.sdk.il/6.0.0-preview.3.21157.6/targets/Microsoft.NET.Sdk.IL.targets(145,5): error MSB3073: The command ""/Users/Hamish/.nuget/packages/runtime.osx-x64.microsoft.netcore.ilasm/6.0.0-preview.3.21157.6/runtimes/osx-x64/native/ilasm" -QUIET -NOLOGO -DLL  -OUTPUT="/Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/ILTestAssembly/x64/Debug/ILTestAssembly.dll"  Main.il ILDisassembler.il InstanceFieldLayout.il StaticFieldLayout.il VirtualFunctionOverride.il Signature.il MethodImplOverride1.il" exited with code 126. [/Users/Hamish/Projects/Clones/runtime/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/ILTestAssembly.ilproj]
  CoreTestAssembly -> /Users/Hamish/Projects/Clones/runtime/artifacts/bin/CoreTestAssembly/x64/Debug/CoreTestAssembly.dll

Build FAILED.

/Users/Hamish/.nuget/packages/microsoft.net.sdk.il/6.0.0-preview.3.21157.6/targets/Microsoft.NET.Sdk.IL.targets(145,5): error MSB3073: The command ""/Users/Hamish/.nuget/packages/runtime.osx-x64.microsoft.netcore.ilasm/6.0.0-preview.3.21157.6/runtimes/osx-x64/native/ilasm" -QUIET -NOLOGO -DLL  -OUTPUT="/Users/Hamish/Projects/Clones/runtime/artifacts/obj/coreclr/ILTestAssembly/x64/Debug/ILTestAssembly.dll"  Main.il ILDisassembler.il InstanceFieldLayout.il StaticFieldLayout.il VirtualFunctionOverride.il Signature.il MethodImplOverride1.il" exited with code 126. [/Users/Hamish/Projects/Clones/runtime/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILTestAssembly/ILTestAssembly.ilproj]
    0 Warning(s)
    1 Error(s)

Edit: the ilasm executable had read/write permissions for system only (must've downloaded this one with sudo), this is probably the issue.

@hamarb123
Copy link
Contributor Author

I'm now able to reproduce the errors in #49555!

@safern
Copy link
Member

safern commented Mar 17, 2021

Thanks @hoyosjs for the help here! From the chat offline with @hoyosjs it seems like paxflags is a Linux thing only, however when this logic was written we didn't know that parallels had a tool named also paxctl 🤣

@hamarb123
Copy link
Contributor Author

My main issue seems to be that I missed the _fileStatusInitialized = -1; line 🤦
Will push the fix shortly to the PR after I've renormalised all of my files.

@danmoseley
Copy link
Member

Good teamwork 🙂

@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Mar 18, 2021
@ghost ghost added in-pr There is an active PR which will close this issue when it is merged and removed in-pr There is an active PR which will close this issue when it is merged labels May 17, 2021
jozkee added a commit that referenced this issue Oct 20, 2021
* Fix setting creation date for OSX

Fix for #39132

* Fix setting creation date for OSX - fix for setattrlist

This commit adds a fallback for setattrlist failing.
It can sometimes fail on specific volume types, so this is a workaround to use the old behaviour on unsupported filesystems.

Fix for #39132

* Fix setting creation date for OSX - fix for caching when set time & possible stack overflow

This commit adds _fileStatusInitialized = -1; which resets the cache for the file status after setting a time value to the file using the setattrlist api version so that it will not simply return the last cached time.
It also fixes SetCreationTime_OtherUnix method so that it calls SetLastWriteTime_OtherUnix directly instead of SetLastWriteTime because otherwise you'll get stuck in an infinite loop on OSX when the fallback is theoretically needed.

Fix for #39132

* Fix setting creation date for OSX - changes for PR 1

Fix the behaviour of SetLastWriteTime (OSX) when setting lastwritetime before creationtime.
Use Invalidate() instead of _fileStatusInitialized = -1, and only when appropriate as per PR #49555.
Add SettingUpdatesPropertiesAfterAnother test to test things such as setting lastwritetime to before creationtime.
Rename the added _OtherUnix methods to _StandardUnixImpl, a more logical name given their purpose (#49555)

Fix for #39132 and issues in #49555.

* Fix setting creation date for OSX - changes for PR 2

Added a new test to test the behaviour of the file time functions on symlinks as per standard Windows behaviour, and also what I use in my code today. It makes sure that the times are set on the symlink itself, not the target. It is likely to fail on many unix platforms, so these will be given the [ActiveIssue] attribute when we discover which ones.
Make access time be set using setattrlist on OSX to fix following symlinks issue that would've failed the new test.
Fix and update wording of comment in SetAccessOrWriteTime.
Add T CreateSymlinkToItem(T item) to BaseGetSetTimes<T> (and implementation in inheritors) for the new test.
Made the SettingUpdatesPropertiesAfterAnother test skip on browser since it only, in effect, has one date attribute.

Fix for #39132 and issues in #49555.

* Fix setting creation date for OSX - changes for PR 3

Revert change in last commit: Make access time be set using setattrlist on OSX to fix following symlinks issue that would've failed the new test. It is now using the other API as otherwise some file watcher tests fail.
Set AT_SYMLINK_NOFOLLOW in pal_time.c to not follow symlinks for access time on OSX, or any times on other unix systems.

* Fix setting creation date for OSX - fix test for Windows and browser + update comments

Fix the SettingUpdatesPropertiesOnSymlink test for Windows by setting FILE_FLAG_OPEN_REPARSE_POINT in the CreateFile used for setting times.
Disable the SettingUpdatesPropertiesOnSymlink test for Browser as it can't use symlinks with the current API in the test project.
Update comments.
Add FILE_FLAG_OPEN_REPARSE_POINT.

Fix for #39132 and issues in #49555.

* Fix setting creation date for OSX - make modification time use normal unix APIs

Only implement creation time setting with setattrlist.
Here is why: eg. the old code doesn't account for setting creation time to 2002, then setting modification time to 2001, and then setting access time (since access time didn't have the creation date check).
I've split up SetAccessOrWriteTime into 3 parts - SetAccessOrWriteTime, SetAccessOrWriteTime_StandardUnixImpl, and SetAccessOrWriteTimeImpl (this last one contains the logic of the method without the things like refreshing the times so it's not called twice on OSX). In this process I replaced the _fileStatusInitialized = -1 calls with Invalidate() calls. And to make sure that if the creation time is needed to be set by SetAccessOrWriteTime, then we don't get in an infinite loop in case setattrlist fails, so we call SetAccessOrWriteTime_StandardUnixImpl.

* Fix setting creation date for OSX - hotfix: Remove ATTR_CMN_MODTIME

Adding this commit now to avoid 2x CI.
It was meant to be in the last one, but I forgot to save the file.

Fix for #39132 and issues in #49555.

* Fix setting creation date for OSX - revert windows changes & simplify code

Revert the changes for Windows & disable the SettingUpdatesPropertiesOnSymlink test on Windows.
Remove unnecessary setting to 0 on the attrList variable.
Remove the unnecessary MarshalAs attributes in the AttrList type.

Fix for #39132 and issues in #49555.

* Fix setting creation date for OSX - hotfix: change to CULong for marshalling with setattrlist

Use CULong as per #49555 (comment)

Fix for #39132 and issues in #49555.

* Fix setting creation date for OSX - hotfix: change to CULong for marshalling with setattrlist 2

Use CULong as per #49555 (comment)
Forgot to save the other file's changes

Fix for #39132 and issues in #49555.

* Fix setting creation date for OSX - consolidate unix nanosecond calculation

Consolidate unix nanosecond calculation into UnixTimeSecondsToNanoseconds as per #49555 (comment).

Fix for #39132 and issues in #49555.

* Use InvalidateCaches instead of Invalidate and EnsureCachesInitialized instead of EnsureStatInitialized

* Fixes for reviews in PR #49555

Add an identifying field to the TimeFunction tuple and a function to get a TimeFunction from the name.
This function is then used so that SettingUpdatesPropertiesAfterAnother can be written as a Theory, and is a lot more readable.
Fix some comments that were incorrect.

* Hotfix for missing parameter

* Fix naming

* Revert changes re SettingUpdatesPropertiesAfterAnother (mainly) and revert using a Theory

Reversion as per #49555 (comment)
This change can be unreverted if that's what's decided.

* Fix errors of #49555 due to missing variables

* Remove the parameters that were meant to be removed

* Finish merge

* Remove duplicate file

* Add custom error handling for setattrlist

Add custom error handling for setattrlist as per #49555 (comment).

ENOTDIR means it is not a directory, so directory not found seems logical to me, I think the other errors can be dealt with by an IOException, happy to change this.

* Remove symlink specific code from this PR

Removes the symlink specific code as per #49555 (comment).
This will be reverted (and modified) as per #49555 (comment) into #52639.

* Remove custom ENOTDIR handling, enable tests for other OSX-like platforms + move items in project file

• Removed ENOTDIR handling as per #49555 (comment)
• Enabled tests for other OSX-like platforms since the code was included on them (IsOSXLike is presumably defined at src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs). If it fails on any of these platforms, they'll be fully explicitly excluded everywhere for this PR or fixed.
• Move item in project file (System.Private.CoreLib.Shared.projitems) as per #49555 (comment)

* Rename files according to review

Rename files according to #49555 (comment) (and nearby comments).

* Change names of functions to improve readability and refactor code

This commit changes and refactors the core functions of this PR to have clearer names and to create a more logical flow of the code. It also updates some comments and fixes some oversights. Changes are based on the discussion #49555 (comment) (read whole conversation).

* Fix the wrongly named variable and add the missing 'unsafe' keyword

Fix the wrongly named variable and add the missing 'unsafe' keyword

* Better comments and minor improvements

Changes according to #49555 (review)
• Use explicit type `IEnumerable<TimeFunction>` instead of var
• Use PlatformDetection rather than OperatingSystem
• Move the InvalidateCaches code for creation time setting to avoid unnecessary checks
• Update explanatory comments to be more useful

* Add additional tests and improvements

- Use tuple destruction to swap variables
- Add SettingOneTimeMaintainsOtherDefaultTimes and AllDefaultTimesAreSame test as per #49555 (comment)
- Change TFM(/s) as per #49555 (comment)
- Avoid unnecessary call to `UnixTimeToDateTimeOffset` as per #49555 (comment)
- Use InvalidOperationException as per #49555 (comment)

* Fix typos

* Revert to <TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser</TargetFrameworks>

Revert to using <TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser</TargetFrameworks> since <TargetFramework>$(NetCoreAppCurrent)</TargetFramework> failed; I wouldn't be surprised if this failed too.

* Remove SettingOneTimeMaintainsOtherDefaultTimes and AllDefaultTimesAreSame tests

Remove SettingOneTimeMaintainsOtherDefaultTimes and AllDefaultTimesAreSame tests since they don't work on windows because it is apparently an invalid time. Additionally, the function SettingOneTimeMaintainsOtherDefaultTimes wasn't working and needed to be fixed.

* Fix: setattrlist can only return 0 or -1

As per #49555 (comment), use GetLastErrorInfo to get the error when setattrlist indicates that there is one.

Co-authored-by: David Cantú <dacantu@microsoft.com>

* Update code comment for SettingUpdatesPropertiesAfterAnother test

The comment is now clearer and grammatically correct :)

* Update code comment for SettingUpdatesPropertiesAfterAnother test

Describe how utimensat change more dates than would be desired

* Update comment for SettingUpdatesPropertiesAfterAnother for consistency

Update for consistency with the comment in FileStatus.Unix.cs

* Fixes for compilation and update to comment

• Fix trailing spaces and incorrect capitalisation in FileStatus.SetTimes.OSX.cs
• Add more info to the comment in the SettingUpdatesPropertiesAfterAnother test

* Update FileStatus.SetTimes.OSX.cs

Use the Error property

* Move comments and add explicit types to SettingUpdatesPropertiesAfterAnother test

Move comments and add explicit types to SettingUpdatesPropertiesAfterAnother test

Co-authored-by: David Cantú <dacantu@microsoft.com>
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Oct 20, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Nov 19, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants