Skip to content

Commit 559747a

Browse files
committed
Support Unix.readlink on Windows
1 parent adbff7e commit 559747a

File tree

5 files changed

+122
-40
lines changed

5 files changed

+122
-40
lines changed

otherlibs/win32unix/Makefile.nt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ WIN_FILES = accept.c bind.c channels.c close.c \
1616
close_on.c connect.c createprocess.c dup.c dup2.c errmsg.c \
1717
getpeername.c getpid.c getsockname.c gettimeofday.c \
1818
link.c listen.c lockf.c lseek.c nonblock.c \
19-
mkdir.c open.c pipe.c read.c rename.c \
19+
mkdir.c open.c pipe.c read.c readlink.c rename.c \
2020
select.c sendrecv.c \
2121
shutdown.c sleep.c socket.c sockopt.c startup.c stat.c \
2222
system.c times.c unixsupport.c windir.c winwait.c write.c \

otherlibs/win32unix/readlink.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/***********************************************************************/
2+
/* */
3+
/* OCaml */
4+
/* */
5+
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
6+
/* */
7+
/* Copyright 1996 Institut National de Recherche en Informatique et */
8+
/* en Automatique. All rights reserved. This file is distributed */
9+
/* under the terms of the GNU Library General Public License, with */
10+
/* the special exception on linking described in file ../../LICENSE. */
11+
/* */
12+
/***********************************************************************/
13+
14+
#include <caml/mlvalues.h>
15+
#include <caml/memory.h>
16+
#include <caml/alloc.h>
17+
#include <caml/fail.h>
18+
#include <caml/signals.h>
19+
#include "unixsupport.h"
20+
#include <errno.h>
21+
#include <winioctl.h>
22+
23+
CAMLprim value unix_readlink(value opath)
24+
{
25+
CAMLparam1(opath);
26+
CAMLlocal1(result);
27+
HANDLE h;
28+
char* path = String_val(opath);
29+
DWORD attributes;
30+
31+
caml_enter_blocking_section();
32+
attributes = GetFileAttributes(path);
33+
caml_leave_blocking_section();
34+
35+
if (attributes == INVALID_FILE_ATTRIBUTES) {
36+
win32_maperr(GetLastError());
37+
uerror("readlink", opath);
38+
}
39+
else if (!(attributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
40+
errno = EINVAL;
41+
uerror("readlink", opath);
42+
}
43+
else {
44+
caml_enter_blocking_section();
45+
if ((h = CreateFile(path, FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL)) == INVALID_HANDLE_VALUE) {
46+
caml_leave_blocking_section();
47+
errno = ENOENT;
48+
uerror("readlink", opath);
49+
}
50+
else {
51+
char buffer[16384];
52+
DWORD read;
53+
REPARSE_DATA_BUFFER* point;
54+
55+
if (DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, 16384, &read, NULL)) {
56+
caml_leave_blocking_section();
57+
point = (REPARSE_DATA_BUFFER*)buffer;
58+
if (point->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
59+
int cbLen = point->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
60+
int len;
61+
len = WideCharToMultiByte(CP_THREAD_ACP, 0, point->SymbolicLinkReparseBuffer.PathBuffer + point->SymbolicLinkReparseBuffer.SubstituteNameOffset / 2, cbLen, NULL, 0, NULL, NULL);
62+
result = caml_alloc_string(len);
63+
WideCharToMultiByte(CP_THREAD_ACP, 0, point->SymbolicLinkReparseBuffer.PathBuffer + point->SymbolicLinkReparseBuffer.SubstituteNameOffset / 2, cbLen, String_val(result), len, NULL, NULL);
64+
CloseHandle(h);
65+
}
66+
else {
67+
errno = EINVAL;
68+
CloseHandle(h);
69+
uerror("readline", opath);
70+
}
71+
}
72+
else {
73+
caml_leave_blocking_section();
74+
win32_maperr(GetLastError());
75+
CloseHandle(h);
76+
uerror("readlink", opath);
77+
}
78+
}
79+
}
80+
81+
CAMLreturn(result);
82+
}

otherlibs/win32unix/stat.c

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -42,44 +42,6 @@
4242
#define S_IFBLK 0
4343
#endif
4444

45-
/*
46-
* This structure is defined inconsistently. mingw64 has it in ntdef.h (which doesn't look like a primary header)
47-
* and technically it's part of ntifs.h in the WDK. Requiring the WDK is a bit extreme, so the definition is
48-
* taken from ntdef.h. Both ntdef.h and ntifs.h define REPARSE_DATA_BUFFER_HEADER_SIZE
49-
*/
50-
#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE
51-
typedef struct _REPARSE_DATA_BUFFER
52-
{
53-
ULONG ReparseTag;
54-
USHORT ReparseDataLength;
55-
USHORT Reserved;
56-
union
57-
{
58-
struct
59-
{
60-
USHORT SubstituteNameOffset;
61-
USHORT SubstituteNameLength;
62-
USHORT PrintNameOffset;
63-
USHORT PrintNameLength;
64-
ULONG Flags;
65-
WCHAR PathBuffer[1];
66-
} SymbolicLinkReparseBuffer;
67-
struct
68-
{
69-
USHORT SubstituteNameOffset;
70-
USHORT SubstituteNameLength;
71-
USHORT PrintNameOffset;
72-
USHORT PrintNameLength;
73-
WCHAR PathBuffer[1];
74-
} MountPointReparseBuffer;
75-
struct
76-
{
77-
UCHAR DataBuffer[1];
78-
} GenericReparseBuffer;
79-
};
80-
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
81-
#endif
82-
8345
static int file_kind_table[] = {
8446
S_IFREG, S_IFDIR, S_IFCHR, S_IFBLK, S_IFLNK, S_IFIFO, S_IFSOCK
8547
};

otherlibs/win32unix/unix.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ let mkfifo name perm = invalid_arg "Unix.mkfifo not implemented"
373373

374374
(* Symbolic links *)
375375

376-
let readlink path = invalid_arg "Unix.readlink not implemented"
376+
external readlink : string -> string = "unix_readlink"
377377
let symlink path1 path2 = invalid_arg "Unix.symlink not implemented"
378378

379379
(* Locking *)

otherlibs/win32unix/unixsupport.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,42 @@ extern value unix_freeze_buffer (value);
7474
}
7575
#endif
7676

77+
/*
78+
* This structure is defined inconsistently. mingw64 has it in ntdef.h (which doesn't look like a primary header)
79+
* and technically it's part of ntifs.h in the WDK. Requiring the WDK is a bit extreme, so the definition is
80+
* taken from ntdef.h. Both ntdef.h and ntifs.h define REPARSE_DATA_BUFFER_HEADER_SIZE
81+
*/
82+
#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE
83+
typedef struct _REPARSE_DATA_BUFFER
84+
{
85+
ULONG ReparseTag;
86+
USHORT ReparseDataLength;
87+
USHORT Reserved;
88+
union
89+
{
90+
struct
91+
{
92+
USHORT SubstituteNameOffset;
93+
USHORT SubstituteNameLength;
94+
USHORT PrintNameOffset;
95+
USHORT PrintNameLength;
96+
ULONG Flags;
97+
WCHAR PathBuffer[1];
98+
} SymbolicLinkReparseBuffer;
99+
struct
100+
{
101+
USHORT SubstituteNameOffset;
102+
USHORT SubstituteNameLength;
103+
USHORT PrintNameOffset;
104+
USHORT PrintNameLength;
105+
WCHAR PathBuffer[1];
106+
} MountPointReparseBuffer;
107+
struct
108+
{
109+
UCHAR DataBuffer[1];
110+
} GenericReparseBuffer;
111+
};
112+
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
113+
#endif
114+
77115
#endif /* CAML_UNIXSUPPORT_H */

0 commit comments

Comments
 (0)