Skip to content

Conversation

@dra27
Copy link
Member

@dra27 dra27 commented Feb 8, 2016

See also the discussion in Mantis

Implements Unix.readlink and Unix.symlink for Windows. Windows symbolic links are a little, both in their implementation and availability - the weirdness of both is documented in unix.mli both in Unix.symlink and the new Unix.has_symlink function.

Microsoft's implementation of stat is, politely put, flaky and there is no implementation of lstat. The stat functions are therefore completely re-implemented - though the algorithm for the Microsoft implementation is maintained in various places (e.g. setting the execute bit). The new implementation populates st_dev using the device's serial number rather than a simulated value and also populates st_ino (critical for ocamlbuild to be able to use the new symbolic link support)

operation. Administrators will always need to be running elevated (or with
UAC disabled) and by default normal user accounts need to be granted the
SeCreateSymbolicLinkPrivilege via Local Security Policy (secpol.msc) or via
Active Directory. *)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you should add that {!has_symlink} can be used to check that the process is able to create symbolic links.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do!

/* */
/* OCaml */
/* */
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to set the correct author here. Is this mostly copied from Xavier's code, or is it substantially new code?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, OK - no, all the code's mine, beyond lifting the GC boilerplate macros from the UNIX version (which is how the header remained). I'll push amendments in a few mins...

@damiendoligez
Copy link
Member

There is a lot of new code in this PR. Have you signed the CLA already? See #342 (comment) for the procedure.

I'm settting the milestone to 4.04 because changes in unix.mli are likely to break some libraries.

@damiendoligez damiendoligez added this to the 4.04-or-later milestone Feb 10, 2016
@dra27
Copy link
Member Author

dra27 commented Feb 10, 2016

Ok, I'll get a CLA pinged to Xavier (will probably be tomorrow as I won't be near a scanner for today). I thought from the comment thread in Mantis that this was approved for 4.03 and just awaiting the fstat change (the patch has been in Mantis for a while) - is it definitely too late for 4.03? It will be useful as it enables support for symlinks in ocamlbuild which eases building for certain libraries in OPAM (but the functionality can of course be back-ported there, it needs be)

@alainfrisch
Copy link
Contributor

because changes in unix.mli are likely to break some libraries.

I'm not sure about the "likely". Except taking the module type of Unix (but this same argument would argue against any change to the stdlib), or passing symlink as a first-class function, how could the changes break existing code? If you are really concerned by the addition of the optional argument, one could probably remove the optional argument for 4.03 (using the default heuristic only).

@dbuenzli
Copy link
Contributor

FWIW I would also very like to have this in 4.03.

@damiendoligez
Copy link
Member

I'm sorry, I forgot to look at the Mantis discussion before I set the milestone. Since we have several Windows stakeholders pushing for inclusion, let's take the risk.

@damiendoligez damiendoligez modified the milestones: 4.03.0, 4.04-or-later Feb 10, 2016
@damiendoligez
Copy link
Member

I'll approve as soon as we have the CLA and you fix the author (and date) in both file headers.

@dra27
Copy link
Member Author

dra27 commented Feb 10, 2016

OK - given that I've almost totally rewritten stat.c, should the header in that be updated too?

@alainfrisch
Copy link
Contributor

@damiendoligez Correct me if I'm wrong, but people contributing code through a CLA should not only update the code attribution but also the copyright holder. Is that right?

@damiendoligez
Copy link
Member

@dra27 Yes, you'll have to update the header in stat.c. And @alainfrisch is correct, you need to put the year and your name in the sentence that starts with Copyright.

@damiendoligez
Copy link
Member

@dra27 This is one of the last 3 things before I branch 4.03, so it would be good if you fixed the headers ASAP. We'll be fine if we have the CLA by Friday or even next Monday.

@dra27
Copy link
Member Author

dra27 commented Feb 10, 2016

Sorry - had to pause for a few hours to do the day job! Should manage this all later this evening...

The mingw64 headers create an inconsistency between the MSVC and MinGW
ports - mingw64 automatically defines _USE_32BIT_TIME_T on 32-bit
Windows, where the Microsoft CRT docs state that should be a user
define. The effect is that the mingw64 32-bit port suffers from the year
2038 bug, where the MSVC 32-bit port does not. Given that OCaml uses a
double for the time fields anyway and OCaml requires sufficiently modern
compilers to be able to rely on a working _stat64 (64-bit time_t and
64-bit st_size), switch from the *i64 to the *64 variants.
Unix.symlink requires CreateSymbolicLink which prevents programs from
running on Windows XP. Dynamically link the function instead.
@dra27
Copy link
Member Author

dra27 commented Feb 10, 2016

Trunk seems to be broken for Windows again, not sure how technically correct this is (given that Windows has FLAMBDA=false in config/Makefile), but I patched trunk thusly for the purposes of testing this:

diff --git a/Makefile.nt b/Makefile.nt
index cda7459..02d8847 100644
--- a/Makefile.nt
+++ b/Makefile.nt
@@ -295,6 +295,14 @@ ocamlc: compilerlibs/ocamlcommon.cma compilerlibs/ocamlbytecomp.cma $(BYTESTART)
 partialclean::
        rm -f ocamlc

+# The middle end (whose .cma library is currently only used for linking
+# the "objinfo" program, since we cannot depend on the whole native code
+# compiler for "make world" and the list of dependencies for
+# asmcomp/export_info.cmo is long).
+
+compilerlibs/ocamlmiddleend.cma: $(MIDDLE_END)
+       $(CAMLC) -a -o $@ $(MIDDLE_END)
+
 # The native-code compiler

 compilerlibs/ocamloptcomp.cma: $(MIDDLE_END) $(ASMCOMP)
@@ -606,7 +614,7 @@ clean::
 # Tools

 ocamltools: ocamlc ocamlyacc ocamllex asmcomp/cmx_format.cmi \
-            asmcomp/printclambda.cmo
+            asmcomp/printclambda.cmo compilerlibs/ocamlmiddleend.cma
        cd tools ; $(MAKEREC) all

 ocamltoolsopt:

@dra27
Copy link
Member Author

dra27 commented Feb 10, 2016

Headers fixed. The only other change, apart from a trunk-rebase, was to remove an obsolete branch of code the algorithm of which was taken from Microsoft's implementation of stat (their old implementation had somewhat weird semantics for UNC and drive roots - e.g. \server\share or C:\ but the new implementation with GetFileInformationByHandle doesn't require such trickery.

For ease of review of the copyright headers, here's the diff:

diff --git a/otherlibs/win32unix/readlink.c b/otherlibs/win32unix/readlink.c
index ad080c5..1bb9347 100644
--- a/otherlibs/win32unix/readlink.c
+++ b/otherlibs/win32unix/readlink.c
@@ -2,12 +2,12 @@
 /*                                                                     */
 /*                                OCaml                                */
 /*                                                                     */
-/*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         */
+/*               David Allsopp, MetaStack Solutions Ltd.               */
 /*                                                                     */
-/*  Copyright 1996 Institut National de Recherche en Informatique et   */
-/*  en Automatique.  All rights reserved.  This file is distributed    */
-/*  under the terms of the GNU Library General Public License, with    */
-/*  the special exception on linking described in file ../../LICENSE.  */
+/*  Copyright 2015 MetaStack Solutions Ltd.  All rights reserved.      */
+/*  This file is distributed under the terms of the GNU Library        */
+/*  General Public License, with the special exception on linking      */
+/*  described in file ../../LICENSE.                                   */
 /*                                                                     */
 /***********************************************************************/

diff --git a/otherlibs/win32unix/stat.c b/otherlibs/win32unix/stat.c
index 432cf21..ed854b8 100644
--- a/otherlibs/win32unix/stat.c
+++ b/otherlibs/win32unix/stat.c
@@ -2,12 +2,12 @@
 /*                                                                     */
 /*                                OCaml                                */
 /*                                                                     */
-/*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         */
+/*               David Allsopp, MetaStack Solutions Ltd.               */
 /*                                                                     */
-/*  Copyright 2002 Institut National de Recherche en Informatique et   */
-/*  en Automatique.  All rights reserved.  This file is distributed    */
-/*  under the terms of the GNU Library General Public License, with    */
-/*  the special exception on linking described in file ../../LICENSE.  */
+/*  Copyright 2015 MetaStack Solutions Ltd.  All rights reserved.      */
+/*  This file is distributed under the terms of the GNU Library        */
+/*  General Public License, with the special exception on linking      */
+/*  described in file ../../LICENSE.                                   */
 /*                                                                     */
 /***********************************************************************/

diff --git a/otherlibs/win32unix/symlink.c b/otherlibs/win32unix/symlink.c
index 37c6810..b684f34 100644
--- a/otherlibs/win32unix/symlink.c
+++ b/otherlibs/win32unix/symlink.c
@@ -2,12 +2,12 @@
 /*                                                                     */
 /*                                OCaml                                */
 /*                                                                     */
-/*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         */
+/*               David Allsopp, MetaStack Solutions Ltd.               */
 /*                                                                     */
-/*  Copyright 1996 Institut National de Recherche en Informatique et   */
-/*  en Automatique.  All rights reserved.  This file is distributed    */
-/*  under the terms of the GNU Library General Public License, with    */
-/*  the special exception on linking described in file ../../LICENSE.  */
+/*  Copyright 2015 MetaStack Solutions Ltd.  All rights reserved.      */
+/*  This file is distributed under the terms of the GNU Library        */
+/*  General Public License, with the special exception on linking      */
+/*  described in file ../../LICENSE.                                   */
 /*                                                                     */
 /***********************************************************************/

@DemiMarie
Copy link
Contributor

Was anything taken from the Microsoft CRT? That code is proprietary, and nothing based on it can be used in OCaml.

@dra27
Copy link
Member Author

dra27 commented Feb 11, 2016

No - the old code in question was mine which allowed an earlier iteration of my do_stat to match the behaviour of Microsoft's (given that there are not many ways of coding 1+1, it was similar) in a particular corner case. Microsoft's freely available (if not libre) source code for the CRT was used to determine the algorithm for corner cases only.
For the avoidance of any copyright doubt, all of the code in this patch is mine with one exception: the REPARSE_DATA_BUFFER structure in otherlibs/win32unix/unixsupport.h which is taken from one of the mingw headers (also see the full structure definition in MSDN) for reasons documented in the comment above it.

damiendoligez added a commit that referenced this pull request Feb 11, 2016
MPR#6120: Windows symlinks and corrected stat implementation
@damiendoligez damiendoligez merged commit 76265a1 into ocaml:trunk Feb 11, 2016
@damiendoligez
Copy link
Member

Thanks a lot!

@dra27 dra27 deleted the pr6120 branch February 11, 2016 13:31
@gasche
Copy link
Member

gasche commented May 9, 2016

I noticed while working on upgrading Batteries for 4.03 that there are some glitches in the unix.mli documentation; for example, readlink is still marked as unsupported on Windows, while I understand that @dra27 added support for it as part of this patch. Would it be possible for someone to fix it?

@damiendoligez
Copy link
Member

readlink is still marked as unsupported on Windows

Fixed in 4.03 branch (525799b).

@fdopen
Copy link
Contributor

fdopen commented Jul 11, 2016

Yes, I know it's late. I'm not sure, if anyone will read this, but.
In readlink/stat/symlink, the path is never copied to the c heap, before caml_enter_blocking_section is called, instead a simple pointer to the caml heap is used. Couldn't caml_enter_blocking_section trigger the garbage collector in case of multiple threads? Or do I miss something obvious?
e.g:

result = pCreateSymbolicLink(String_val(dest), String_val(source), flags);
,
if (!do_stat(0, 0, String_val(path), caml_string_length(path), NULL, &st_ino, &buf)) {
,
h = CreateFile(path,
,
if ((h = CreateFile(path,
, etc.

@alainfrisch
Copy link
Contributor

I believe you are right, and this should be fixed. Would you like to propose a patch?

@dra27
Copy link
Member Author

dra27 commented Jul 11, 2016

Gah - good spot. In all those cases, there's no choice but duplicate the string, I guess. Is caml_enter_blocking_section a no-op when threading isn't in use, or can garbage collection take place between caml_enter_blocking_section...caml_leave_blocking_section even in single-threaded code?
There's at least one other instance, looking at https://github.com/ocaml/ocaml/blob/trunk/otherlibs/win32unix/sleep.c#L23-L25, I think?
Happy to put a patch together (it's my mess...!)

@xavierleroy
Copy link
Contributor

@dra27: between enter_blocking_section/leave_blocking_section, both context switches and signal handling can take place, so you should assume that a GC can occur. Copying the Caml string is indeed necessary. The run-time cost of the copy is negligible compared with the cost of the system call.

For Unix.sleep, you're correct that Double_val(t) should be computed before caml_enter_blocking_section.

@damiendoligez
Copy link
Member

I've opened a pair of Mantis issues to track these bugs:

@dra27
Copy link
Member Author

dra27 commented Jul 22, 2016

@xavierleroy - thanks for the confirmation!
@damiendoligez - I'll submit PRs using those reference numbers. Should manage them both before I go on holiday next week (and therefore in time for 4.04?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants