Updated ntdll-Junction_Points patchset

This commit is contained in:
Alistair Leslie-Hughes 2019-05-10 08:57:46 +10:00
parent 992845eae7
commit 082a898ad4
25 changed files with 1007 additions and 389 deletions

View File

@ -1,4 +1,4 @@
From 935694ac40ed4b264ef0ede519bd8b9b2f1f28de Mon Sep 17 00:00:00 2001
From 78f4401a1e5d50097be8dd8458273ef1d4a548a7 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Tue, 19 Aug 2014 22:10:49 -0600
Subject: [PATCH] ntdll: Implement retrieving DOS attributes in
@ -6,15 +6,15 @@ Subject: [PATCH] ntdll: Implement retrieving DOS attributes in
---
configure.ac | 12 ++++++++++++
dlls/ntdll/file.c | 22 +++++++++++++++++++++-
dlls/ntdll/file.c | 16 ++++++++++++++++
include/wine/port.h | 8 ++++++++
libs/port/Makefile.in | 4 +++-
libs/port/xattr.c | 39 +++++++++++++++++++++++++++++++++++++++
5 files changed, 83 insertions(+), 2 deletions(-)
5 files changed, 78 insertions(+), 1 deletion(-)
create mode 100644 libs/port/xattr.c
diff --git a/configure.ac b/configure.ac
index 1905733..6f0429e 100644
index 9385d20..60d43d3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,6 +85,7 @@ AC_ARG_WITH(udev, AS_HELP_STRING([--without-udev],[do not use udev (plug an
@ -25,7 +25,7 @@ index 1905733..6f0429e 100644
AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xcomposite extension]),
[if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi])
AC_ARG_WITH(xcursor, AS_HELP_STRING([--without-xcursor],[do not use the Xcursor extension]),
@@ -698,6 +699,17 @@ AC_CHECK_HEADERS([libprocstat.h],,,
@@ -711,6 +712,17 @@ AC_CHECK_HEADERS([libprocstat.h],,,
#include <sys/socket.h>
#endif])
@ -44,7 +44,7 @@ index 1905733..6f0429e 100644
AC_SUBST(DLLFLAGS,"-D_REENTRANT")
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 919eaea..1ffa675 100644
index b70477e..2c99c1d 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -127,6 +127,22 @@ static const WCHAR ntfsW[] = {'N','T','F','S'};
@ -70,24 +70,6 @@ index 919eaea..1ffa675 100644
/* fetch the attributes of a file */
static inline ULONG get_file_attributes( const struct stat *st )
{
@@ -144,12 +160,16 @@ static inline ULONG get_file_attributes( const struct stat *st )
/* get the stat info and file attributes for a file (by file descriptor) */
int fd_get_file_info( int fd, struct stat *st, ULONG *attr )
{
- int ret;
+ char hexattr[11];
+ int len, ret;
*attr = 0;
ret = fstat( fd, st );
if (ret == -1) return ret;
*attr |= get_file_attributes( st );
+ len = xattr_fget( fd, SAMBA_XATTR_DOS_ATTRIB, hexattr, sizeof(hexattr)-1 );
+ if (len == -1) return ret;
+ *attr |= get_file_xattr( hexattr, len );
return ret;
}
diff --git a/include/wine/port.h b/include/wine/port.h
index 19c8682..eaa23bc 100644
--- a/include/wine/port.h

View File

@ -1,7 +1,8 @@
From c65dec8465c321f09ee3bfd0317994da8cd0c0c1 Mon Sep 17 00:00:00 2001
From 347997c4118fa01fbf87cf7cadb6ba04a83a97c4 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 20 Aug 2014 00:08:52 -0600
Subject: ntdll: Implement storing DOS attributes in NtSetInformationFile.
Subject: [PATCH] ntdll: Implement storing DOS attributes in
NtSetInformationFile.
---
dlls/ntdll/file.c | 54 +++++++++++++++++++++++++++++++------------------
@ -11,11 +12,11 @@ Subject: ntdll: Implement storing DOS attributes in NtSetInformationFile.
4 files changed, 60 insertions(+), 24 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index b977e45..521ab64 100644
index 6743d37..12d47ae 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -149,6 +149,39 @@ int fd_get_file_info( int fd, struct stat *st, ULONG *attr )
return ret;
@@ -157,6 +157,39 @@ static inline ULONG get_file_attributes( const struct stat *st )
return attr;
}
+/* set the stat info and file attributes for a file (by file descriptor) */
@ -54,7 +55,7 @@ index b977e45..521ab64 100644
/* get the stat info and file attributes for a file (by name) */
int get_file_info( const char *path, struct stat *st, ULONG *attr )
{
@@ -2320,7 +2353,6 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
@@ -3097,7 +3130,6 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
case FileBasicInformation:
if (len >= sizeof(FILE_BASIC_INFORMATION))
{
@ -62,7 +63,7 @@ index b977e45..521ab64 100644
const FILE_BASIC_INFORMATION *info = ptr;
if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
@@ -2330,25 +2362,7 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
@@ -3107,25 +3139,7 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
io->u.Status = set_file_times( fd, &info->LastWriteTime, &info->LastAccessTime );
if (io->u.Status == STATUS_SUCCESS && info->FileAttributes)
@ -90,10 +91,10 @@ index b977e45..521ab64 100644
if (needs_close) close( fd );
}
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index d70ed6b..7a8e5d4 100644
index d0646aa..39f9013 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -1234,7 +1234,7 @@ static void test_file_basic_information(void)
@@ -1341,7 +1341,7 @@ static void test_file_basic_information(void)
memset(&fbi, 0, sizeof(fbi));
res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation);
ok ( res == STATUS_SUCCESS, "can't get attributes\n");
@ -102,7 +103,7 @@ index d70ed6b..7a8e5d4 100644
/* Then HIDDEN */
memset(&fbi, 0, sizeof(fbi));
@@ -1247,7 +1247,7 @@ static void test_file_basic_information(void)
@@ -1354,7 +1354,7 @@ static void test_file_basic_information(void)
memset(&fbi, 0, sizeof(fbi));
res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation);
ok ( res == STATUS_SUCCESS, "can't get attributes\n");
@ -111,7 +112,7 @@ index d70ed6b..7a8e5d4 100644
/* Check NORMAL last of all (to make sure we can clear attributes) */
memset(&fbi, 0, sizeof(fbi));
@@ -1304,7 +1304,7 @@ static void test_file_all_information(void)
@@ -1411,7 +1411,7 @@ static void test_file_all_information(void)
memset(&fai_buf.fai, 0, sizeof(fai_buf.fai));
res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation);
ok ( res == STATUS_SUCCESS, "can't get attributes, res %x\n", res);
@ -120,7 +121,7 @@ index d70ed6b..7a8e5d4 100644
/* Then HIDDEN */
memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation));
@@ -1317,7 +1317,7 @@ static void test_file_all_information(void)
@@ -1424,7 +1424,7 @@ static void test_file_all_information(void)
memset(&fai_buf.fai, 0, sizeof(fai_buf.fai));
res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation);
ok ( res == STATUS_SUCCESS, "can't get attributes\n");
@ -130,10 +131,10 @@ index d70ed6b..7a8e5d4 100644
/* Check NORMAL last of all (to make sure we can clear attributes) */
memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation));
diff --git a/include/wine/port.h b/include/wine/port.h
index 7977eb9..cc572f3 100644
index de6b995..c075958 100644
--- a/include/wine/port.h
+++ b/include/wine/port.h
@@ -370,6 +370,8 @@ extern int _spawnvp(int mode, const char *cmdname, const char * const argv[]);
@@ -351,6 +351,8 @@ extern int mkstemps(char *template, int suffix_len);
#endif
extern int xattr_fget( int filedes, const char *name, void *value, size_t size );

View File

@ -1,4 +1,4 @@
From 87bbbc7d6c67c2ec3e13f84a7eecccb71e486ac0 Mon Sep 17 00:00:00 2001
From 589bbdea7af00507d3dce26feec1c6db1d8e9746 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 20:56:49 -0700
Subject: ntdll: Add support for junction point creation.
@ -18,10 +18,10 @@ Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
create mode 100644 libs/port/renameat2.c
diff --git a/configure.ac b/configure.ac
index d1502bacf7..84307f0f54 100644
index 0ad8417735..39a9571a95 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2207,6 +2207,8 @@ AC_CHECK_FUNCS(\
@@ -2206,6 +2206,8 @@ AC_CHECK_FUNCS(\
pwrite \
readdir \
readlink \
@ -305,10 +305,10 @@ index 8e54dbb541..322dadefe3 100644
+ test_reparse_points();
}
diff --git a/include/Makefile.in b/include/Makefile.in
index 4a0f927082..519a34c856 100644
index 979695f552..2a1382e811 100644
--- a/include/Makefile.in
+++ b/include/Makefile.in
@@ -480,6 +480,7 @@ SOURCES = \
@@ -482,6 +482,7 @@ SOURCES = \
ntddvdeo.h \
ntdef.h \
ntdsapi.h \

View File

@ -1,4 +1,4 @@
From 38245bc3099137dd16dc78e3f41c6d50b7f0f804 Mon Sep 17 00:00:00 2001
From 56730d38b6326cee609916af394a37d4559d249e Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 20:57:57 -0700
Subject: ntdll: Add support for reading junction points.

View File

@ -1,4 +1,4 @@
From 9f0a95668d86bacd6cd006e6fe6c6d463cfb5e9b Mon Sep 17 00:00:00 2001
From 424814c370108dcad48290dc203adff96672dea9 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 21:00:21 -0700
Subject: ntdll: Add support for deleting junction points.

View File

@ -1,4 +1,4 @@
From 52fb88dc16f22188dd2b3800fc1cd0034dbd118e Mon Sep 17 00:00:00 2001
From 3e60e844c4ce938fb12ff09d561967a75e110f82 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 21:01:25 -0700
Subject: ntdll: Add a test for junction point advertisement.

View File

@ -1,4 +1,4 @@
From db064094e068f3e6434f4b4302c5b2eadf8395ef Mon Sep 17 00:00:00 2001
From f0ac5c57f3a0c2ddb542ed1cc1e78513ad4a60fe Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 21:02:11 -0700
Subject: kernel32,ntdll: Add support for deleting junction points with

View File

@ -1,4 +1,4 @@
From aa5ad3e25315a3ca2113df9a80e178fdfef58296 Mon Sep 17 00:00:00 2001
From 944851b4f7cda627c3c35a6735f14121b87d0148 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 21:03:47 -0700
Subject: kernel32: Advertise junction point support.
@ -9,7 +9,7 @@ Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
1 file changed, 84 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/volume.c b/dlls/kernel32/volume.c
index 12084369cb..76bb32b850 100644
index 4fd913aa22..437832e5c9 100644
--- a/dlls/kernel32/volume.c
+++ b/dlls/kernel32/volume.c
@@ -44,6 +44,19 @@

View File

@ -1,4 +1,4 @@
From 8547ee103b062ae2c8e1a5fd058ea3e9dc8a2146 Mon Sep 17 00:00:00 2001
From 7183c92e5f02346e8d72432a602fb7dfc3659a5b Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 21:06:24 -0700
Subject: ntdll: Add support for absolute symlink creation.

View File

@ -1,4 +1,4 @@
From b9fa01baf73dc3975bd56b9b0ce0d26eddb45e81 Mon Sep 17 00:00:00 2001
From d3129f74304e5fa5ba33eb51bd4ef1e9bfce1b8f Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 13 Mar 2019 12:55:20 -0600
Subject: ntdll: Add support for reading absolute symlinks.

View File

@ -1,4 +1,4 @@
From 90921ac6aba0f98fb9b33104c82d77e07cc82278 Mon Sep 17 00:00:00 2001
From 9bc86ef7b245595248c0f5b157c9a57f4ce0c8aa Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 13 Mar 2019 13:02:22 -0600
Subject: ntdll: Add support for deleting symlinks.

View File

@ -1,4 +1,4 @@
From 4cfe8631a57057a13afa650f41576c8c3ae465d5 Mon Sep 17 00:00:00 2001
From 0879c8d8575ba4ff1b7e9f408679c4fb92468f62 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 11 Apr 2019 12:16:49 -0600
Subject: ntdll: Add support for relative symlink creation.

View File

@ -1,4 +1,4 @@
From cdd6070ee2b8876877c66bfdaa44b4b152633b1d Mon Sep 17 00:00:00 2001
From 7c02ce3203b8796455d12423b960b720e90a9639 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 11 Apr 2019 12:31:16 -0600
Subject: ntdll: Add support for reading relative symlinks.

View File

@ -1,4 +1,4 @@
From 05a16c210c3dabb07cc5b5514e9745f00fb364ea Mon Sep 17 00:00:00 2001
From ac69cecc3f024819efae83723b77d9f310b43251 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 11 Apr 2019 17:57:53 -0600
Subject: ntdll: Add support for file symlinks.
@ -92,7 +92,7 @@ index 5df2d8c3fa..03a07d46cd 100644
lchown( tmpfile, st.st_uid, st.st_gid );
/* Atomically move the directory into position */
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index c13ee84bf0..f40dc1f51b 100644
index c13ee84bf0..5bf8ebf704 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5050,6 +5050,39 @@ static void test_reparse_points(void)
@ -106,7 +106,7 @@ index c13ee84bf0..f40dc1f51b 100644
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ win_skip("Failed to open symlink directory handle (0x%x).\n", GetLastError());
+ win_skip("Failed to open symlink file handle (0x%x).\n", GetLastError());
+ goto cleanup;
+ }
+ dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);

View File

@ -0,0 +1,68 @@
From 1cb09e87cf0fd0a805849f3483d2b3b7bed5ec18 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Tue, 30 Apr 2019 16:24:54 -0600
Subject: ntdll: Allow creation of dangling reparse points to non-existent
paths.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/directory.c | 14 ++++++++++++++
dlls/ntdll/file.c | 3 ++-
include/winternl.h | 1 +
3 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
index bbdbbe9781..cca1e3c4a8 100644
--- a/dlls/ntdll/directory.c
+++ b/dlls/ntdll/directory.c
@@ -2705,6 +2705,20 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
status = STATUS_OBJECT_NAME_COLLISION;
}
}
+ else if (disposition == FILE_WINE_PATH && status == STATUS_OBJECT_PATH_NOT_FOUND)
+ {
+ ret = ntdll_wcstoumbs( 0, name, end - name, unix_name + pos + 1,
+ MAX_DIR_ENTRY_LEN, NULL, &used_default );
+ if (ret > 0 && !used_default)
+ {
+ unix_name[pos] = '/';
+ unix_name[pos + 1 + ret] = 0;
+ status = STATUS_NO_SUCH_FILE;
+ pos += strlen( unix_name + pos );
+ name = next;
+ continue;
+ }
+ }
if (status != STATUS_SUCCESS) break;
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 03a07d46cd..04d34dd572 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -1722,8 +1722,9 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
RtlCreateUnicodeString( &nt_dest, dest );
nt_dest.Length = dest_len;
}
+
nt_dest_allocated = TRUE;
- status = wine_nt_to_unix_file_name( &nt_dest, &unix_dest, 0, FALSE );
+ status = wine_nt_to_unix_file_name( &nt_dest, &unix_dest, FILE_WINE_PATH, FALSE );
if (status != STATUS_SUCCESS && status != STATUS_NO_SUCH_FILE)
goto cleanup;
dest_allocated = TRUE;
diff --git a/include/winternl.h b/include/winternl.h
index 2b3fb947b9..7f6b2f57ba 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -1788,6 +1788,7 @@ typedef struct _RTL_HANDLE_TABLE
#define FILE_OVERWRITE 4
#define FILE_OVERWRITE_IF 5
#define FILE_MAXIMUM_DISPOSITION 5
+#define FILE_WINE_PATH 6
/* Characteristics of a File System */
#define FILE_REMOVABLE_MEDIA 0x00000001
--
2.17.1

View File

@ -1,16 +1,16 @@
From 9c0229cf831240320ef2797dbfd21493d7871088 Mon Sep 17 00:00:00 2001
From 20171f2a705fdf94966e9661d360ac70bb92cb8e Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Sat, 30 Mar 2019 12:00:51 -0600
Subject: ntdll: Correctly report file symbolic links as files.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 110 +++++++++++++++++++++++++++-------------
dlls/ntdll/file.c | 118 ++++++++++++++++++++++++++--------------
dlls/ntdll/tests/file.c | 8 +--
2 files changed, 79 insertions(+), 39 deletions(-)
2 files changed, 82 insertions(+), 44 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 03a07d46cd..8b78306fbf 100644
index 04d34dd572..8336392ddb 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -124,6 +124,9 @@ mode_t FILE_umask = 0;
@ -23,22 +23,25 @@ index 03a07d46cd..8b78306fbf 100644
/* fetch the attributes of a file */
static inline ULONG get_file_attributes( const struct stat *st )
{
@@ -160,10 +163,14 @@ int get_file_info( const char *path, struct stat *st, ULONG *attr )
@@ -160,10 +163,13 @@ int get_file_info( const char *path, struct stat *st, ULONG *attr )
if (ret == -1) return ret;
if (S_ISLNK( st->st_mode ))
{
- ret = stat( path, st );
- if (ret == -1) return ret;
- /* is a symbolic link and a directory, consider these "reparse points" */
- if (S_ISDIR( st->st_mode )) *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
+ BOOL is_dir;
+
ret = stat( path, st );
if (ret == -1) return ret;
/* is a symbolic link and a directory, consider these "reparse points" */
if (S_ISDIR( st->st_mode )) *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
+ if (FILE_DecodeSymlink( path, NULL, NULL, NULL, NULL, &is_dir) == STATUS_SUCCESS)
+ /* symbolic links (either junction points or NT symlinks) are "reparse points" */
+ *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
+ /* whether a reparse point is a file or a directory is stored inside the link target */
+ if (FILE_DecodeSymlink( path, NULL, NULL, NULL, NULL, &is_dir ) == STATUS_SUCCESS)
+ st->st_mode = (st->st_mode & ~S_IFMT) | (is_dir ? S_IFDIR : S_IFREG);
}
*attr |= get_file_attributes( st );
return ret;
@@ -1825,48 +1832,34 @@ cleanup:
@@ -1826,48 +1832,33 @@ cleanup:
}
@ -78,13 +81,13 @@ index 03a07d46cd..8b78306fbf 100644
- unix_dest.MaximumLength = PATH_MAX;
- dest_allocated = TRUE;
- ret = readlink( unix_src.Buffer, unix_dest.Buffer, unix_dest.MaximumLength );
- if (ret < 0)
+ if (unix_dest_len) len = *unix_dest_len;
+ if (!unix_dest)
+ tmp = RtlAllocateHeap( GetProcessHeap(), 0, len );
+ else
+ tmp = unix_dest;
+ ret = readlink( unix_src, tmp, len );
if (ret < 0)
+ if ((ret = readlink( unix_src, tmp, len )) < 0)
{
status = FILE_GetNtStatus();
goto cleanup;
@ -102,7 +105,7 @@ index 03a07d46cd..8b78306fbf 100644
p++;
}
if (*p++ != '/')
@@ -1874,7 +1867,7 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
@@ -1875,7 +1866,7 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
status = STATUS_NOT_IMPLEMENTED;
goto cleanup;
}
@ -111,7 +114,7 @@ index 03a07d46cd..8b78306fbf 100644
for (i = 0; i < sizeof(ULONG)*8; i++)
{
char c = *p++;
@@ -1889,21 +1882,68 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
@@ -1890,21 +1881,68 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
status = STATUS_NOT_IMPLEMENTED;
goto cleanup;
}
@ -186,7 +189,7 @@ index 03a07d46cd..8b78306fbf 100644
/* convert the relative path into an absolute path */
if (flags == SYMLINK_FLAG_RELATIVE)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index f40dc1f51b..f23bf8644c 100644
index 5bf8ebf704..bacfad266e 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5069,13 +5069,13 @@ static void test_reparse_points(void)

View File

@ -0,0 +1,137 @@
From 4f8611e2dfc7fb70e13a6f05949257e5d441328a Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 1 May 2019 19:46:03 -0600
Subject: ntdll: Correctly report fd-based file info for symlinks.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 64 ++++++++++++++++++++++++++++++++++-------------
1 file changed, 46 insertions(+), 18 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 8336392ddb..934577bfba 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -141,18 +141,6 @@ static inline ULONG get_file_attributes( const struct stat *st )
return attr;
}
-/* get the stat info and file attributes for a file (by file descriptor) */
-int fd_get_file_info( int fd, struct stat *st, ULONG *attr )
-{
- int ret;
-
- *attr = 0;
- ret = fstat( fd, st );
- if (ret == -1) return ret;
- *attr |= get_file_attributes( st );
- return ret;
-}
-
/* get the stat info and file attributes for a file (by name) */
int get_file_info( const char *path, struct stat *st, ULONG *attr )
{
@@ -175,6 +163,46 @@ int get_file_info( const char *path, struct stat *st, ULONG *attr )
return ret;
}
+/* get the stat info and file attributes for a file (by file descriptor) */
+int fd_get_file_info( HANDLE h, int fd, struct stat *st, ULONG *attr )
+{
+ ANSI_STRING unix_src;
+ struct stat tmp;
+ int ret = -1;
+
+ /* if this handle is to a symlink then we need to return information about the symlink */
+ if (server_get_unix_name( h, &unix_src ) != STATUS_SUCCESS)
+ return ret;
+ ret = get_file_info( unix_src.Buffer, st, attr);
+ RtlFreeAnsiString( &unix_src );
+ if (ret == -1) return ret;
+ /* but return the times from the file itself */
+ ret = fstat( fd, &tmp );
+ if (ret == -1) return ret;
+#if defined(HAVE_STRUCT_STAT_ST_ATIM)
+ st->st_atim = tmp.st_atim;
+#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
+ st->st_atimespec = tmp.st_atimespec;
+#else
+ st->st_atime = tmp.st_atime;
+#endif
+#if defined(HAVE_STRUCT_STAT_ST_MTIM)
+ st->st_mtim = tmp.st_mtim;
+#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
+ st->st_mtimespec = tmp.st_mtimespec;
+#else
+ st->st_mtime = tmp.st_mtime;
+#endif
+#if defined(HAVE_STRUCT_STAT_ST_CTIM)
+ st->st_ctim = tmp.st_ctim;
+#elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
+ st->st_ctimespec = tmp.st_ctimespec;
+#else
+ st->st_ctime = tmp.st_ctime;
+#endif
+ return ret;
+}
+
/**************************************************************************
* FILE_CreateFile (internal)
* Open a file.
@@ -2832,7 +2860,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
switch (class)
{
case FileBasicInformation:
- if (fd_get_file_info( fd, &st, &attr ) == -1)
+ if (fd_get_file_info( hFile, fd, &st, &attr ) == -1)
io->u.Status = FILE_GetNtStatus();
else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
io->u.Status = STATUS_INVALID_INFO_CLASS;
@@ -2843,7 +2871,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
{
FILE_STANDARD_INFORMATION *info = ptr;
- if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
+ if (fd_get_file_info( hFile, fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else
{
fill_file_info( &st, attr, info, class );
@@ -2860,7 +2888,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
}
break;
case FileInternalInformation:
- if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
+ if (fd_get_file_info( hFile, fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else fill_file_info( &st, attr, ptr, class );
break;
case FileEaInformation:
@@ -2870,7 +2898,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
}
break;
case FileEndOfFileInformation:
- if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
+ if (fd_get_file_info( hFile, fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else fill_file_info( &st, attr, ptr, class );
break;
case FileAllInformation:
@@ -2878,7 +2906,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
FILE_ALL_INFORMATION *info = ptr;
ANSI_STRING unix_name;
- if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
+ if (fd_get_file_info( hFile, fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
io->u.Status = STATUS_INVALID_INFO_CLASS;
else if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
@@ -2986,7 +3014,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
}
break;
case FileIdInformation:
- if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
+ if (fd_get_file_info( hFile, fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else
{
FILE_ID_INFORMATION *info = ptr;
--
2.17.1

View File

@ -1,288 +0,0 @@
From 99b54adfcc2740af27224957748f94a0e84b47c3 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 13 Mar 2019 16:02:05 -0600
Subject: kernel32: Implement CreateSymbolicLink[A|W] with ntdll reparse
points.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/kernel32/path.c | 124 +++++++++++++++++++++++++++++++++++--
dlls/kernel32/tests/path.c | 94 ++++++++++++++++++++++++++++
2 files changed, 214 insertions(+), 4 deletions(-)
diff --git a/dlls/kernel32/path.c b/dlls/kernel32/path.c
index f15b6dd68b..d96471e4c6 100644
--- a/dlls/kernel32/path.c
+++ b/dlls/kernel32/path.c
@@ -34,6 +34,8 @@
#include "windef.h"
#include "winbase.h"
#include "winternl.h"
+#include "winioctl.h"
+#include "ntifs.h"
#include "kernel_private.h"
#include "wine/unicode.h"
@@ -2087,8 +2089,106 @@ WCHAR * CDECL wine_get_dos_file_name( LPCSTR str )
*/
BOOLEAN WINAPI CreateSymbolicLinkW(LPCWSTR link, LPCWSTR target, DWORD flags)
{
- FIXME("(%s %s %d): stub\n", debugstr_w(link), debugstr_w(target), flags);
- return TRUE;
+ static INT struct_size = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer[0]);
+ static INT header_size = offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer);
+ INT buffer_size, data_size, string_len, prefix_len;
+ WCHAR *subst_dest, *print_dest, *string;
+ REPARSE_DATA_BUFFER *buffer;
+ LPWSTR target_path = NULL;
+ BOOL is_relative, is_dir;
+ int target_path_len = 0;
+ UNICODE_STRING nt_name;
+ BOOLEAN bret = FALSE;
+ NTSTATUS status;
+ HANDLE hlink;
+ DWORD dwret;
+
+ TRACE("(%s %s %d)\n", debugstr_w(link), debugstr_w(target), flags);
+
+ is_relative = (RtlDetermineDosPathNameType_U( target ) == RELATIVE_PATH);
+ is_dir = (flags & SYMBOLIC_LINK_FLAG_DIRECTORY);
+ if (is_dir && !CreateDirectoryW( link, NULL ))
+ return FALSE;
+ hlink = CreateFileW( link, GENERIC_READ | GENERIC_WRITE, 0, 0,
+ is_dir ? OPEN_EXISTING : CREATE_NEW,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0 );
+ if (hlink == INVALID_HANDLE_VALUE)
+ goto cleanup;
+ if (is_relative)
+ {
+ UNICODE_STRING nt_path;
+ int len;
+
+ status = RtlDosPathNameToNtPathName_U_WithStatus( link, &nt_path, NULL, NULL );
+ if (status != STATUS_SUCCESS)
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ goto cleanup;
+ }
+ /* obtain the path of the link */
+ for (; nt_path.Length > 0; nt_path.Length -= sizeof(WCHAR))
+ {
+ WCHAR c = nt_path.Buffer[nt_path.Length/sizeof(WCHAR)];
+ if (c == '/' || c == '\\')
+ {
+ nt_path.Length += sizeof(WCHAR);
+ break;
+ }
+ }
+ /* append the target to the link path */
+ target_path_len = nt_path.Length / sizeof(WCHAR);
+ len = target_path_len + (strlenW( target ) + 1);
+ target_path = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(WCHAR) );
+ lstrcpynW( target_path, nt_path.Buffer, nt_path.Length );
+ target_path[nt_path.Length/sizeof(WCHAR)] = 0;
+ lstrcatW( target_path, target );
+ RtlFreeUnicodeString( &nt_path );
+ }
+ else
+ target_path = (LPWSTR)target;
+ status = RtlDosPathNameToNtPathName_U_WithStatus( target_path, &nt_name, NULL, NULL );
+ if (status != STATUS_SUCCESS)
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ goto cleanup;
+ }
+ if (is_relative && strncmpW( target_path, nt_name.Buffer, target_path_len ) != 0)
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ goto cleanup;
+ }
+ prefix_len = is_relative ? 0 : strlen("\\??\\");
+ string = &nt_name.Buffer[target_path_len];
+ string_len = lstrlenW( &string[prefix_len] );
+ data_size = (prefix_len + 2 * string_len + 2) * sizeof(WCHAR);
+ buffer_size = struct_size + data_size;
+ buffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_size );
+ buffer->ReparseTag = IO_REPARSE_TAG_SYMLINK;
+ buffer->ReparseDataLength = struct_size - header_size + data_size;
+ buffer->SymbolicLinkReparseBuffer.SubstituteNameLength = (prefix_len + string_len) * sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.PrintNameOffset = (prefix_len + string_len + 1) * sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.PrintNameLength = string_len * sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.Flags = is_relative ? SYMLINK_FLAG_RELATIVE : 0;
+ subst_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[0];
+ print_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[prefix_len + string_len + 1];
+ lstrcpyW( subst_dest, string );
+ lstrcpyW( print_dest, &string[prefix_len] );
+ RtlFreeUnicodeString( &nt_name );
+ bret = DeviceIoControl( hlink, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_size, NULL, 0,
+ &dwret, 0 );
+ CloseHandle( hlink );
+ HeapFree( GetProcessHeap(), 0, buffer );
+
+cleanup:
+ if (!bret)
+ {
+ if (is_dir)
+ RemoveDirectoryW( link );
+ else
+ DeleteFileW( link );
+ }
+ if (is_relative) HeapFree( GetProcessHeap(), 0, target_path );
+ return bret;
}
/*************************************************************************
@@ -2096,8 +2196,24 @@ BOOLEAN WINAPI CreateSymbolicLinkW(LPCWSTR link, LPCWSTR target, DWORD flags)
*/
BOOLEAN WINAPI CreateSymbolicLinkA(LPCSTR link, LPCSTR target, DWORD flags)
{
- FIXME("(%s %s %d): stub\n", debugstr_a(link), debugstr_a(target), flags);
- return TRUE;
+ WCHAR *targetW, *linkW;
+ BOOL ret;
+
+ TRACE("(%s %s %d)\n", debugstr_a(link), debugstr_a(target), flags);
+
+ if (!(linkW = FILE_name_AtoW( link, TRUE )))
+ {
+ return FALSE;
+ }
+ if (!(targetW = FILE_name_AtoW( target, TRUE )))
+ {
+ HeapFree( GetProcessHeap(), 0, linkW );
+ return FALSE;
+ }
+ ret = CreateSymbolicLinkW( linkW, targetW, flags );
+ HeapFree( GetProcessHeap(), 0, linkW );
+ HeapFree( GetProcessHeap(), 0, targetW );
+ return ret;
}
/*************************************************************************
diff --git a/dlls/kernel32/tests/path.c b/dlls/kernel32/tests/path.c
index 0a03225120..076333b3b1 100644
--- a/dlls/kernel32/tests/path.c
+++ b/dlls/kernel32/tests/path.c
@@ -81,6 +81,9 @@ static void (WINAPI *pReleaseActCtx)(HANDLE);
static BOOL (WINAPI *pCheckNameLegalDOS8Dot3W)(const WCHAR *, char *, DWORD, BOOL *, BOOL *);
static BOOL (WINAPI *pCheckNameLegalDOS8Dot3A)(const char *, char *, DWORD, BOOL *, BOOL *);
+/* Present in Vista+ */
+static BOOL (WINAPI *pCreateSymbolicLinkW)(LPCWSTR, LPCWSTR, DWORD);
+
/* a structure to deal with wine todos somewhat cleanly */
typedef struct {
DWORD shortlen;
@@ -2179,6 +2182,7 @@ static void init_pointers(void)
MAKEFUNC(ReleaseActCtx);
MAKEFUNC(CheckNameLegalDOS8Dot3W);
MAKEFUNC(CheckNameLegalDOS8Dot3A);
+ MAKEFUNC(CreateSymbolicLinkW);
#undef MAKEFUNC
}
@@ -2435,6 +2439,95 @@ static void test_SetSearchPathMode(void)
RemoveDirectoryA( dir );
}
+static void test_CreateSymbolicLink(void)
+{
+ static const WCHAR target_fileW[] = {'t','a','r','g','e','t','_','f','i','l','e',0};
+ static const WCHAR target_dirW[] = {'t','a','r','g','e','t','_','d','i','r',0};
+ static const WCHAR linkW[] = {'l','i','n','k',0};
+ static const WCHAR fooW[] = {'f','o','o',0};
+ static WCHAR volW[] = {'c',':','\\',0};
+ static const WCHAR dotW[] = {'.',0};
+ WCHAR path[MAX_PATH], old_path[MAX_PATH], tmp[MAX_PATH];
+ DWORD dwLen, dwFlags;
+ TOKEN_PRIVILEGES tp;
+ HANDLE token;
+ LUID luid;
+ BOOL bret;
+ HANDLE h;
+
+ if (!pCreateSymbolicLinkW)
+ {
+ win_skip( "CreateSymbolicLink isn't available\n" );
+ return;
+ }
+
+ /* Create a temporary folder for the symlink tests */
+ GetTempFileNameW( dotW, fooW, 0, path );
+ DeleteFileW( path );
+ if (!CreateDirectoryW( path, NULL ))
+ {
+ win_skip("Unable to create a temporary junction point directory.\n");
+ return;
+ }
+ GetCurrentDirectoryW( sizeof(old_path)/sizeof(WCHAR), old_path );
+ SetCurrentDirectoryW( path );
+
+ /* Check that the volume this folder is located on supports reparse points */
+ GetFullPathNameW( path, sizeof(tmp)/sizeof(WCHAR), tmp, NULL );
+ volW[0] = tmp[0];
+ GetVolumeInformationW( volW, 0, 0, 0, &dwLen, &dwFlags, 0, 0 );
+ if (!(dwFlags & FILE_SUPPORTS_REPARSE_POINTS))
+ {
+ skip("File system does not support junction points.\n");
+ goto cleanup;
+ }
+
+ /* Establish permissions for symlink creation */
+ bret = OpenProcessToken( GetCurrentProcess(), TOKEN_ALL_ACCESS, &token );
+ ok(bret, "OpenProcessToken failed: %u\n", GetLastError());
+ bret = LookupPrivilegeValueA( NULL, "SeCreateSymbolicLinkPrivilege", &luid );
+ todo_wine ok(bret || broken(!bret && GetLastError() == ERROR_NO_SUCH_PRIVILEGE) /* winxp */,
+ "LookupPrivilegeValue failed: %u\n", GetLastError());
+ if (bret)
+ {
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Luid = luid;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ bret = AdjustTokenPrivileges( token, FALSE, &tp, 0, NULL, NULL );
+ ok(bret, "AdjustTokenPrivileges failed: %u\n", GetLastError());
+ }
+ if ((!bret && GetLastError() != ERROR_NO_SUCH_PRIVILEGE) || GetLastError() == ERROR_NOT_ALL_ASSIGNED)
+ {
+ win_skip("Insufficient permissions to perform symlink tests.\n");
+ goto cleanup;
+ }
+
+ /* Create a destination folder and file for symlinks to target */
+ bret = CreateDirectoryW( target_dirW, NULL );
+ ok(bret, "Failed to create symlink target directory.\n");
+ h = CreateFileW( target_fileW, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
+ ok(h != INVALID_HANDLE_VALUE, "Failed to create symlink target file.\n");
+ CloseHandle( h );
+
+ /* Create a directory symbolic link */
+ bret = CreateSymbolicLinkW( linkW, target_dirW, SYMBOLIC_LINK_FLAG_DIRECTORY );
+ ok(bret, "Failed to create directory symbolic link! (0x%x)\n", GetLastError());
+ bret = RemoveDirectoryW( linkW );
+ ok(bret, "Failed to remove directory symbolic link! (0x%x)\n", GetLastError());
+
+ /* Create a file symbolic link */
+ bret = CreateSymbolicLinkW( linkW, target_fileW, 0x0 );
+ ok(bret, "Failed to create file symbolic link! (0x%x)\n", GetLastError());
+ bret = DeleteFileW( linkW );
+ ok(bret, "Failed to remove file symbolic link! (0x%x)\n", GetLastError());
+
+cleanup:
+ DeleteFileW( target_fileW );
+ RemoveDirectoryW( target_dirW );
+ SetCurrentDirectoryW( old_path );
+ RemoveDirectoryW( path );
+}
+
START_TEST(path)
{
CHAR origdir[MAX_PATH],curdir[MAX_PATH], curDrive, otherDrive;
@@ -2469,4 +2562,5 @@ START_TEST(path)
test_GetFullPathNameW();
test_CheckNameLegalDOS8Dot3();
test_SetSearchPathMode();
+ test_CreateSymbolicLink();
}
--
2.17.1

View File

@ -1,4 +1,4 @@
From e34db8f28e43091a02cccb2eb590f9beda9da059 Mon Sep 17 00:00:00 2001
From 417a71fe5c16121c85bf59c13f610ebcdf701508 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Sat, 30 Mar 2019 12:01:50 -0600
Subject: kernel32: Set error code when attempting to delete file symlinks as
@ -27,7 +27,7 @@ index 76a9512c77..f15b6dd68b 100644
}
else
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index f23bf8644c..a1323ab4f6 100644
index bacfad266e..2f5ee0618c 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5071,9 +5071,9 @@ static void test_reparse_points(void)

View File

@ -1,4 +1,4 @@
From 245f8c8ad1d014bbf726020fd4c37c99e8bcafea Mon Sep 17 00:00:00 2001
From 160758d1973e49d5bb9d76d203fe1d0a8f676240 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Sat, 30 Mar 2019 13:41:07 -0600
Subject: server: Properly handle file symlink deletion.
@ -6,11 +6,11 @@ Subject: server: Properly handle file symlink deletion.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 6 ++--
server/fd.c | 64 +++++++++++++++++++++++++++++++++++++----
2 files changed, 62 insertions(+), 8 deletions(-)
server/fd.c | 75 ++++++++++++++++++++++++++++++++++++++---
2 files changed, 73 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index a1323ab4f6..8ab8a5da53 100644
index 2f5ee0618c..5f42ad5e0b 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5080,14 +5080,14 @@ static void test_reparse_points(void)
@ -32,10 +32,21 @@ index a1323ab4f6..8ab8a5da53 100644
/* Create the directory symlink */
HeapFree(GetProcessHeap(), 0, buffer);
diff --git a/server/fd.c b/server/fd.c
index 5d80e218b9..71347e4318 100644
index 5d80e218b9..e74fef6a19 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1069,7 +1069,7 @@ static void inode_destroy( struct object *obj )
@@ -105,6 +105,10 @@
#include "winternl.h"
#include "winioctl.h"
+#if !defined(O_SYMLINK) && defined(O_PATH)
+# define O_SYMLINK (O_NOFOLLOW | O_PATH)
+#endif
+
#if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_EPOLL_CREATE)
# include <sys/epoll.h>
# define USE_EPOLL
@@ -1069,7 +1073,7 @@ static void inode_destroy( struct object *obj )
{
/* make sure it is still the same file */
struct stat st;
@ -44,7 +55,7 @@ index 5d80e218b9..71347e4318 100644
{
if (S_ISDIR(st.st_mode)) rmdir( fd->unix_name );
else unlink( fd->unix_name );
@@ -1747,6 +1747,53 @@ char *dup_fd_name( struct fd *root, const char *name )
@@ -1747,6 +1751,53 @@ char *dup_fd_name( struct fd *root, const char *name )
return ret;
}
@ -98,7 +109,21 @@ index 5d80e218b9..71347e4318 100644
/* open() wrapper that returns a struct fd with no fd user set */
struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode, unsigned int access,
unsigned int sharing, unsigned int options )
@@ -1826,14 +1873,15 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
@@ -1815,6 +1866,13 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
if ((access & FILE_UNIX_WRITE_ACCESS) || (flags & O_CREAT))
fd->unix_fd = open( name, O_RDONLY | (flags & ~(O_TRUNC | O_CREAT | O_EXCL)), *mode );
}
+#if defined(O_SYMLINK)
+ /* if we tried to open a dangling symlink then try again with O_SYMLINK */
+ else if (errno == ENOENT)
+ {
+ fd->unix_fd = open( name, rw_mode | O_SYMLINK | (flags & ~O_TRUNC), *mode );
+ }
+#endif
if (fd->unix_fd == -1)
{
@@ -1826,14 +1884,15 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
closed_fd->unix_fd = fd->unix_fd;
closed_fd->unlink = 0;
closed_fd->unix_name = fd->unix_name;
@ -116,7 +141,7 @@ index 5d80e218b9..71347e4318 100644
if (!inode)
{
@@ -1848,13 +1896,19 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
@@ -1848,13 +1907,19 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
list_add_head( &inode->open, &fd->inode_entry );
closed_fd = NULL;

View File

@ -0,0 +1,93 @@
From 5eb8e81e70075947729f70e59825d472db8faf2a Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 1 May 2019 12:06:20 -0600
Subject: ntdll: Always report symbolic links as containing zero bytes.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 2 ++
dlls/ntdll/tests/file.c | 27 +++++++++++++++++++++++++--
2 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 934577bfba..cf98b1cfdd 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -153,6 +153,8 @@ int get_file_info( const char *path, struct stat *st, ULONG *attr )
{
BOOL is_dir;
+ /* symbolic links always report size 0 */
+ st->st_size = 0;
/* symbolic links (either junction points or NT symlinks) are "reparse points" */
*attr |= FILE_ATTRIBUTE_REPARSE_POINT;
/* whether a reparse point is a file or a directory is stored inside the link target */
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 5f42ad5e0b..36c021acd7 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -4897,6 +4897,7 @@ static void test_reparse_points(void)
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags, err;
INT buffer_len, string_len;
+ WCHAR buf[] = {0,0,0,0};
HANDLE handle, token;
IO_STATUS_BLOCK iosb;
UNICODE_STRING nameW;
@@ -5024,8 +5025,6 @@ static void test_reparse_points(void)
"Unexpected junction point attributes (0x%x != 0x410)!\n", dwret);
bret = RemoveDirectoryW(target_path);
ok(bret, "Failed to delete junction point target!\n");
- bret = CreateDirectoryW(target_path, NULL);
- ok(bret, "Failed to create junction point target directory.\n");
/* Establish permissions for symlink creation */
bret = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token);
@@ -5050,6 +5049,13 @@ static void test_reparse_points(void)
/* Delete the junction point directory and create a blank slate for symlink tests */
bret = RemoveDirectoryW(reparse_path);
ok(bret, "Failed to delete junction point!\n");
+ handle = CreateFileW(target_path, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, 0, 0);
+ ok(handle != INVALID_HANDLE_VALUE, "Failed to create symlink target file.\n");
+ bret = WriteFile(handle, fooW, sizeof(fooW), NULL, NULL);
+ ok(bret, "Failed to write data to the symlink target file.\n");
+ ok(GetFileSize(handle, NULL) == sizeof(fooW), "target size is incorrect (%d vs %d)\n",
+ GetFileSize(handle, NULL), sizeof(fooW));
+ CloseHandle(handle);
/* Create the file symlink */
HeapFree(GetProcessHeap(), 0, buffer);
@@ -5067,6 +5073,19 @@ static void test_reparse_points(void)
ok(bret, "Failed to create symlink! (0x%x)\n", GetLastError());
CloseHandle(handle);
+ /* Check the size of the symlink */
+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ ok(handle != INVALID_HANDLE_VALUE, "Failed to open symlink file.\n");
+ ok(GetFileSize(handle, NULL) == 0, "symlink size is not zero\n");
+ bret = ReadFile(handle, &buf, sizeof(buf), &dwLen, NULL);
+ ok(bret, "Failed to read data from the symlink.\n");
+ ok(dwLen == sizeof(fooW), "Length of symlink target data does not match (%d != %d).\n",
+ dwLen, sizeof(fooW));
+ ok(!memcmp(fooW, &buf, sizeof(fooW)), "Symlink target data does not match (%s != %s).\n",
+ wine_dbgstr_wn(buf, dwLen), wine_dbgstr_w(fooW));
+ CloseHandle(handle);
+
/* Check deleting a file symlink as if it were a directory */
bret = RemoveDirectoryW(reparse_path);
ok(!bret, "Succeeded in deleting file symlink as a directory!\n");
@@ -5088,6 +5107,10 @@ static void test_reparse_points(void)
dwret = GetFileAttributesW(reparse_path);
ok(dwret != (DWORD)~0, "Path doesn't exist (attributes: 0x%x)!\n", dwret);
ok(!(dwret & FILE_ATTRIBUTE_REPARSE_POINT), "File is already a reparse point! (attributes: %d)\n", dwret);
+ bret = DeleteFileW(target_path);
+ ok(bret, "Failed to delete symlink target!\n");
+ bret = CreateDirectoryW(target_path, NULL);
+ ok(bret, "Failed to create symlink target directory.\n");
/* Create the directory symlink */
HeapFree(GetProcessHeap(), 0, buffer);
--
2.17.1

View File

@ -0,0 +1,47 @@
From e573ccae4f2584e7f7c040f1c1f986d1e7ebdc6e Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 1 May 2019 17:48:51 -0600
Subject: ntdll: Find dangling symlinks quickly.
This is also necessary on systems (such as MacOS) that support
case-insensitive lookups of files.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/directory.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
index cca1e3c4a8..8f16f5e310 100644
--- a/dlls/ntdll/directory.c
+++ b/dlls/ntdll/directory.c
@@ -2052,7 +2052,7 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
if (ret >= 0 && !used_default)
{
unix_name[pos + ret] = 0;
- if (!stat( unix_name, &st ))
+ if (!lstat( unix_name, &st ))
{
if (is_win_dir) *is_win_dir = is_same_file( &windir, &st );
return STATUS_SUCCESS;
@@ -2174,7 +2174,7 @@ not_found:
return STATUS_OBJECT_PATH_NOT_FOUND;
success:
- if (is_win_dir && !stat( unix_name, &st )) *is_win_dir = is_same_file( &windir, &st );
+ if (is_win_dir && !lstat( unix_name, &st )) *is_win_dir = is_same_file( &windir, &st );
return STATUS_SUCCESS;
}
@@ -2640,7 +2640,7 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
for (p = unix_name + pos ; *p; p++) if (*p == '\\') *p = '/';
if (!name_len || !redirect || (!strstr( unix_name, "/windows/") && strncmp( unix_name, "windows/", 8 )))
{
- if (!stat( unix_name, &st ))
+ if (!lstat( unix_name, &st ))
{
if (disposition == FILE_CREATE)
return STATUS_OBJECT_NAME_COLLISION;
--
2.17.1

View File

@ -0,0 +1,542 @@
From 3b19992c3906902dfb452360c0e0b22d31ab0a6e Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 13 Mar 2019 16:02:05 -0600
Subject: kernel32: Implement CreateSymbolicLink[A|W] with ntdll reparse
points.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/kernel32/path.c | 124 +++++++++++++++++++++++++++++++--
dlls/kernel32/tests/path.c | 94 +++++++++++++++++++++++++
dlls/msvcp120/tests/msvcp120.c | 75 +++++++++-----------
dlls/msvcp140/tests/msvcp140.c | 63 +++++++----------
4 files changed, 275 insertions(+), 81 deletions(-)
diff --git a/dlls/kernel32/path.c b/dlls/kernel32/path.c
index f15b6dd68b..71661ad540 100644
--- a/dlls/kernel32/path.c
+++ b/dlls/kernel32/path.c
@@ -34,6 +34,8 @@
#include "windef.h"
#include "winbase.h"
#include "winternl.h"
+#include "winioctl.h"
+#include "ntifs.h"
#include "kernel_private.h"
#include "wine/unicode.h"
@@ -2087,8 +2089,106 @@ WCHAR * CDECL wine_get_dos_file_name( LPCSTR str )
*/
BOOLEAN WINAPI CreateSymbolicLinkW(LPCWSTR link, LPCWSTR target, DWORD flags)
{
- FIXME("(%s %s %d): stub\n", debugstr_w(link), debugstr_w(target), flags);
- return TRUE;
+ static INT struct_size = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer[0]);
+ static INT header_size = offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer);
+ INT buffer_size, data_size, string_len, prefix_len;
+ WCHAR *subst_dest, *print_dest, *string;
+ REPARSE_DATA_BUFFER *buffer;
+ LPWSTR target_path = NULL;
+ BOOL is_relative, is_dir;
+ int target_path_len = 0;
+ UNICODE_STRING nt_name;
+ BOOLEAN bret = FALSE;
+ NTSTATUS status;
+ HANDLE hlink;
+ DWORD dwret;
+
+ TRACE("(%s %s %d)\n", debugstr_w(link), debugstr_w(target), flags);
+
+ is_relative = (RtlDetermineDosPathNameType_U( target ) == RELATIVE_PATH);
+ is_dir = (flags & SYMBOLIC_LINK_FLAG_DIRECTORY);
+ if (is_dir && !CreateDirectoryW( link, NULL ))
+ return FALSE;
+ hlink = CreateFileW( link, GENERIC_READ | GENERIC_WRITE, 0, 0,
+ is_dir ? OPEN_EXISTING : CREATE_NEW,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0 );
+ if (hlink == INVALID_HANDLE_VALUE)
+ goto cleanup;
+ if (is_relative)
+ {
+ UNICODE_STRING nt_path;
+ int len;
+
+ status = RtlDosPathNameToNtPathName_U_WithStatus( link, &nt_path, NULL, NULL );
+ if (status != STATUS_SUCCESS)
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ goto cleanup;
+ }
+ /* obtain the path of the link */
+ for (; nt_path.Length > 0; nt_path.Length -= sizeof(WCHAR))
+ {
+ WCHAR c = nt_path.Buffer[nt_path.Length/sizeof(WCHAR)];
+ if (c == '/' || c == '\\')
+ {
+ nt_path.Length += sizeof(WCHAR);
+ break;
+ }
+ }
+ /* append the target to the link path */
+ target_path_len = nt_path.Length / sizeof(WCHAR);
+ len = target_path_len + (strlenW( target ) + 1);
+ target_path = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(WCHAR) );
+ lstrcpynW( target_path, nt_path.Buffer, target_path_len+1 );
+ target_path[target_path_len+1] = 0;
+ lstrcatW( target_path, target );
+ RtlFreeUnicodeString( &nt_path );
+ }
+ else
+ target_path = (LPWSTR)target;
+ status = RtlDosPathNameToNtPathName_U_WithStatus( target_path, &nt_name, NULL, NULL );
+ if (status != STATUS_SUCCESS)
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ goto cleanup;
+ }
+ if (is_relative && strncmpW( target_path, nt_name.Buffer, target_path_len ) != 0)
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ goto cleanup;
+ }
+ prefix_len = is_relative ? 0 : strlen("\\??\\");
+ string = &nt_name.Buffer[target_path_len];
+ string_len = lstrlenW( &string[prefix_len] );
+ data_size = (prefix_len + 2 * string_len + 2) * sizeof(WCHAR);
+ buffer_size = struct_size + data_size;
+ buffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_size );
+ buffer->ReparseTag = IO_REPARSE_TAG_SYMLINK;
+ buffer->ReparseDataLength = struct_size - header_size + data_size;
+ buffer->SymbolicLinkReparseBuffer.SubstituteNameLength = (prefix_len + string_len) * sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.PrintNameOffset = (prefix_len + string_len + 1) * sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.PrintNameLength = string_len * sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.Flags = is_relative ? SYMLINK_FLAG_RELATIVE : 0;
+ subst_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[0];
+ print_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[prefix_len + string_len + 1];
+ lstrcpyW( subst_dest, string );
+ lstrcpyW( print_dest, &string[prefix_len] );
+ RtlFreeUnicodeString( &nt_name );
+ bret = DeviceIoControl( hlink, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_size, NULL, 0,
+ &dwret, 0 );
+ HeapFree( GetProcessHeap(), 0, buffer );
+
+cleanup:
+ CloseHandle( hlink );
+ if (!bret)
+ {
+ if (is_dir)
+ RemoveDirectoryW( link );
+ else
+ DeleteFileW( link );
+ }
+ if (is_relative) HeapFree( GetProcessHeap(), 0, target_path );
+ return bret;
}
/*************************************************************************
@@ -2096,8 +2196,24 @@ BOOLEAN WINAPI CreateSymbolicLinkW(LPCWSTR link, LPCWSTR target, DWORD flags)
*/
BOOLEAN WINAPI CreateSymbolicLinkA(LPCSTR link, LPCSTR target, DWORD flags)
{
- FIXME("(%s %s %d): stub\n", debugstr_a(link), debugstr_a(target), flags);
- return TRUE;
+ WCHAR *targetW, *linkW;
+ BOOL ret;
+
+ TRACE("(%s %s %d)\n", debugstr_a(link), debugstr_a(target), flags);
+
+ if (!(linkW = FILE_name_AtoW( link, TRUE )))
+ {
+ return FALSE;
+ }
+ if (!(targetW = FILE_name_AtoW( target, TRUE )))
+ {
+ HeapFree( GetProcessHeap(), 0, linkW );
+ return FALSE;
+ }
+ ret = CreateSymbolicLinkW( linkW, targetW, flags );
+ HeapFree( GetProcessHeap(), 0, linkW );
+ HeapFree( GetProcessHeap(), 0, targetW );
+ return ret;
}
/*************************************************************************
diff --git a/dlls/kernel32/tests/path.c b/dlls/kernel32/tests/path.c
index 8f5508355b..6664ca7d3f 100644
--- a/dlls/kernel32/tests/path.c
+++ b/dlls/kernel32/tests/path.c
@@ -81,6 +81,9 @@ static void (WINAPI *pReleaseActCtx)(HANDLE);
static BOOL (WINAPI *pCheckNameLegalDOS8Dot3W)(const WCHAR *, char *, DWORD, BOOL *, BOOL *);
static BOOL (WINAPI *pCheckNameLegalDOS8Dot3A)(const char *, char *, DWORD, BOOL *, BOOL *);
+/* Present in Vista+ */
+static BOOL (WINAPI *pCreateSymbolicLinkW)(LPCWSTR, LPCWSTR, DWORD);
+
/* a structure to deal with wine todos somewhat cleanly */
typedef struct {
DWORD shortlen;
@@ -2202,6 +2205,7 @@ static void init_pointers(void)
MAKEFUNC(ReleaseActCtx);
MAKEFUNC(CheckNameLegalDOS8Dot3W);
MAKEFUNC(CheckNameLegalDOS8Dot3A);
+ MAKEFUNC(CreateSymbolicLinkW);
#undef MAKEFUNC
}
@@ -2458,6 +2462,95 @@ static void test_SetSearchPathMode(void)
RemoveDirectoryA( dir );
}
+static void test_CreateSymbolicLink(void)
+{
+ static const WCHAR target_fileW[] = {'t','a','r','g','e','t','_','f','i','l','e',0};
+ static const WCHAR target_dirW[] = {'t','a','r','g','e','t','_','d','i','r',0};
+ static const WCHAR linkW[] = {'l','i','n','k',0};
+ static const WCHAR fooW[] = {'f','o','o',0};
+ static WCHAR volW[] = {'c',':','\\',0};
+ static const WCHAR dotW[] = {'.',0};
+ WCHAR path[MAX_PATH], old_path[MAX_PATH], tmp[MAX_PATH];
+ DWORD dwLen, dwFlags;
+ TOKEN_PRIVILEGES tp;
+ HANDLE token;
+ LUID luid;
+ BOOL bret;
+ HANDLE h;
+
+ if (!pCreateSymbolicLinkW)
+ {
+ win_skip( "CreateSymbolicLink isn't available\n" );
+ return;
+ }
+
+ /* Create a temporary folder for the symlink tests */
+ GetTempFileNameW( dotW, fooW, 0, path );
+ DeleteFileW( path );
+ if (!CreateDirectoryW( path, NULL ))
+ {
+ win_skip("Unable to create a temporary junction point directory.\n");
+ return;
+ }
+ GetCurrentDirectoryW( sizeof(old_path)/sizeof(WCHAR), old_path );
+ SetCurrentDirectoryW( path );
+
+ /* Check that the volume this folder is located on supports reparse points */
+ GetFullPathNameW( path, sizeof(tmp)/sizeof(WCHAR), tmp, NULL );
+ volW[0] = tmp[0];
+ GetVolumeInformationW( volW, 0, 0, 0, &dwLen, &dwFlags, 0, 0 );
+ if (!(dwFlags & FILE_SUPPORTS_REPARSE_POINTS))
+ {
+ skip("File system does not support junction points.\n");
+ goto cleanup;
+ }
+
+ /* Establish permissions for symlink creation */
+ bret = OpenProcessToken( GetCurrentProcess(), TOKEN_ALL_ACCESS, &token );
+ ok(bret, "OpenProcessToken failed: %u\n", GetLastError());
+ bret = LookupPrivilegeValueA( NULL, "SeCreateSymbolicLinkPrivilege", &luid );
+ todo_wine ok(bret || broken(!bret && GetLastError() == ERROR_NO_SUCH_PRIVILEGE) /* winxp */,
+ "LookupPrivilegeValue failed: %u\n", GetLastError());
+ if (bret)
+ {
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Luid = luid;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ bret = AdjustTokenPrivileges( token, FALSE, &tp, 0, NULL, NULL );
+ ok(bret, "AdjustTokenPrivileges failed: %u\n", GetLastError());
+ }
+ if ((!bret && GetLastError() != ERROR_NO_SUCH_PRIVILEGE) || GetLastError() == ERROR_NOT_ALL_ASSIGNED)
+ {
+ win_skip("Insufficient permissions to perform symlink tests.\n");
+ goto cleanup;
+ }
+
+ /* Create a destination folder and file for symlinks to target */
+ bret = CreateDirectoryW( target_dirW, NULL );
+ ok(bret, "Failed to create symlink target directory.\n");
+ h = CreateFileW( target_fileW, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
+ ok(h != INVALID_HANDLE_VALUE, "Failed to create symlink target file.\n");
+ CloseHandle( h );
+
+ /* Create a directory symbolic link */
+ bret = CreateSymbolicLinkW( linkW, target_dirW, SYMBOLIC_LINK_FLAG_DIRECTORY );
+ ok(bret, "Failed to create directory symbolic link! (0x%x)\n", GetLastError());
+ bret = RemoveDirectoryW( linkW );
+ ok(bret, "Failed to remove directory symbolic link! (0x%x)\n", GetLastError());
+
+ /* Create a file symbolic link */
+ bret = CreateSymbolicLinkW( linkW, target_fileW, 0x0 );
+ ok(bret, "Failed to create file symbolic link! (0x%x)\n", GetLastError());
+ bret = DeleteFileW( linkW );
+ ok(bret, "Failed to remove file symbolic link! (0x%x)\n", GetLastError());
+
+cleanup:
+ DeleteFileW( target_fileW );
+ RemoveDirectoryW( target_dirW );
+ SetCurrentDirectoryW( old_path );
+ RemoveDirectoryW( path );
+}
+
START_TEST(path)
{
CHAR origdir[MAX_PATH],curdir[MAX_PATH], curDrive, otherDrive;
@@ -2492,4 +2585,5 @@ START_TEST(path)
test_GetFullPathNameW();
test_CheckNameLegalDOS8Dot3();
test_SetSearchPathMode();
+ test_CreateSymbolicLink();
}
diff --git a/dlls/msvcp120/tests/msvcp120.c b/dlls/msvcp120/tests/msvcp120.c
index c416a1020b..e0c97ebcaa 100644
--- a/dlls/msvcp120/tests/msvcp120.c
+++ b/dlls/msvcp120/tests/msvcp120.c
@@ -1636,15 +1636,14 @@ static void test_tr2_sys__Stat(void)
char const *path;
enum file_type ret;
int err_code;
- int is_todo;
} tests[] = {
- { NULL, status_unknown, ERROR_INVALID_PARAMETER, FALSE },
- { "tr2_test_dir", directory_file, ERROR_SUCCESS, FALSE },
- { "tr2_test_dir\\f1", regular_file, ERROR_SUCCESS, FALSE },
- { "tr2_test_dir\\not_exist_file ", file_not_found, ERROR_SUCCESS, FALSE },
- { "tr2_test_dir\\??invalid_name>>", file_not_found, ERROR_SUCCESS, FALSE },
- { "tr2_test_dir\\f1_link" , regular_file, ERROR_SUCCESS, TRUE },
- { "tr2_test_dir\\dir_link", directory_file, ERROR_SUCCESS, TRUE },
+ { NULL, status_unknown, ERROR_INVALID_PARAMETER },
+ { "tr2_test_dir", directory_file, ERROR_SUCCESS },
+ { "tr2_test_dir\\f1", regular_file, ERROR_SUCCESS },
+ { "tr2_test_dir\\not_exist_file ", file_not_found, ERROR_SUCCESS },
+ { "tr2_test_dir\\??invalid_name>>", file_not_found, ERROR_SUCCESS },
+ { "tr2_test_dir\\f1_link" , regular_file, ERROR_SUCCESS },
+ { "tr2_test_dir\\dir_link", directory_file, ERROR_SUCCESS },
};
WCHAR testW[] = {'t','r','2','_','t','e','s','t','_','d','i','r',0};
WCHAR testW2[] = {'t','r','2','_','t','e','s','t','_','d','i','r','/','f','1',0};
@@ -1689,16 +1688,14 @@ static void test_tr2_sys__Stat(void)
for(i=0; i<ARRAY_SIZE(tests); i++) {
err_code = 0xdeadbeef;
val = p_tr2_sys__Stat(tests[i].path, &err_code);
- todo_wine_if(tests[i].is_todo)
- ok(tests[i].ret == val, "tr2_sys__Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
+ ok(tests[i].ret == val, "tr2_sys__Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
ok(tests[i].err_code == err_code, "tr2_sys__Stat(): test %d err_code expect: %d, got %d\n",
i+1, tests[i].err_code, err_code);
/* test tr2_sys__Lstat */
err_code = 0xdeadbeef;
val = p_tr2_sys__Lstat(tests[i].path, &err_code);
- todo_wine_if(tests[i].is_todo)
- ok(tests[i].ret == val, "tr2_sys__Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
+ ok(tests[i].ret == val, "tr2_sys__Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
ok(tests[i].err_code == err_code, "tr2_sys__Lstat(): test %d err_code expect: %d, got %d\n",
i+1, tests[i].err_code, err_code);
}
@@ -1713,8 +1710,8 @@ static void test_tr2_sys__Stat(void)
ok(ERROR_SUCCESS == err_code, "tr2_sys__Lstat_wchar(): err_code expect ERROR_SUCCESS, got %d\n", err_code);
if(ret) {
- todo_wine ok(DeleteFileA("tr2_test_dir/f1_link"), "expect tr2_test_dir/f1_link to exist\n");
- todo_wine ok(RemoveDirectoryA("tr2_test_dir/dir_link"), "expect tr2_test_dir/dir_link to exist\n");
+ ok(DeleteFileA("tr2_test_dir/f1_link"), "expect tr2_test_dir/f1_link to exist\n");
+ ok(RemoveDirectoryA("tr2_test_dir/dir_link"), "expect tr2_test_dir/dir_link to exist\n");
}
ok(DeleteFileA("tr2_test_dir/f1"), "expect tr2_test_dir/f1 to exist\n");
ok(RemoveDirectoryA("tr2_test_dir"), "expect tr2_test_dir to exist\n");
@@ -1944,16 +1941,15 @@ static void test_tr2_sys__Symlink(void)
char const *existing_path;
char const *new_path;
int last_error;
- MSVCP_bool is_todo;
} tests[] = {
- { "f1", "f1_link", ERROR_SUCCESS, FALSE },
- { "f1", "tr2_test_dir\\f1_link", ERROR_SUCCESS, FALSE },
- { "tr2_test_dir\\f1_link", "tr2_test_dir\\f1_link_link", ERROR_SUCCESS, FALSE },
- { "tr2_test_dir", "dir_link", ERROR_SUCCESS, FALSE },
- { NULL, "NULL_link", ERROR_INVALID_PARAMETER, FALSE },
- { "f1", NULL, ERROR_INVALID_PARAMETER, FALSE },
- { "not_exist", "not_exist_link", ERROR_SUCCESS, FALSE },
- { "f1", "not_exist_dir\\f1_link", ERROR_PATH_NOT_FOUND, TRUE }
+ { "f1", "f1_link", ERROR_SUCCESS },
+ { "f1", "tr2_test_dir\\f1_link", ERROR_SUCCESS },
+ { "tr2_test_dir\\f1_link", "tr2_test_dir\\f1_link_link", ERROR_SUCCESS },
+ { "tr2_test_dir", "dir_link", ERROR_SUCCESS },
+ { NULL, "NULL_link", ERROR_INVALID_PARAMETER },
+ { "f1", NULL, ERROR_INVALID_PARAMETER },
+ { "not_exist", "not_exist_link", ERROR_SUCCESS },
+ { "f1", "not_exist_dir\\f1_link", ERROR_PATH_NOT_FOUND }
};
ret = p_tr2_sys__Make_dir("tr2_test_dir");
@@ -1978,18 +1974,17 @@ static void test_tr2_sys__Symlink(void)
}
ok(errno == 0xdeadbeef, "tr2_sys__Symlink(): test %d errno expect 0xdeadbeef, got %d\n", i+1, errno);
- todo_wine_if(tests[i].is_todo)
- ok(ret == tests[i].last_error, "tr2_sys__Symlink(): test %d expect: %d, got %d\n", i+1, tests[i].last_error, ret);
+ ok(ret == tests[i].last_error, "tr2_sys__Symlink(): test %d expect: %d, got %d\n", i+1, tests[i].last_error, ret);
if(ret == ERROR_SUCCESS)
ok(p_tr2_sys__File_size(tests[i].new_path) == 0, "tr2_sys__Symlink(): expect 0, got %s\n", wine_dbgstr_longlong(p_tr2_sys__File_size(tests[i].new_path)));
}
ok(DeleteFileA("f1"), "expect f1 to exist\n");
- todo_wine ok(DeleteFileA("f1_link"), "expect f1_link to exist\n");
- todo_wine ok(DeleteFileA("tr2_test_dir/f1_link"), "expect tr2_test_dir/f1_link to exist\n");
- todo_wine ok(DeleteFileA("tr2_test_dir/f1_link_link"), "expect tr2_test_dir/f1_link_link to exist\n");
- todo_wine ok(DeleteFileA("not_exist_link"), "expect not_exist_link to exist\n");
- todo_wine ok(DeleteFileA("dir_link"), "expect dir_link to exist\n");
+ ok(DeleteFileA("f1_link"), "expect f1_link to exist\n");
+ ok(DeleteFileA("tr2_test_dir/f1_link"), "expect tr2_test_dir/f1_link to exist\n");
+ ok(DeleteFileA("tr2_test_dir/f1_link_link"), "expect tr2_test_dir/f1_link_link to exist\n");
+ ok(DeleteFileA("not_exist_link"), "expect not_exist_link to exist\n");
+ ok(DeleteFileA("dir_link"), "expect dir_link to exist\n");
ret = p_tr2_sys__Remove_dir("tr2_test_dir");
ok(ret == 1, "tr2_sys__Remove_dir(): expect 1 got %d\n", ret);
}
@@ -2003,15 +1998,14 @@ static void test_tr2_sys__Unlink(void)
struct {
char const *path;
int last_error;
- MSVCP_bool is_todo;
} tests[] = {
- { "tr2_test_dir\\f1_symlink", ERROR_SUCCESS, TRUE },
- { "tr2_test_dir\\f1_link", ERROR_SUCCESS, FALSE },
- { "tr2_test_dir\\f1", ERROR_SUCCESS, FALSE },
- { "tr2_test_dir", ERROR_ACCESS_DENIED, FALSE },
- { "not_exist", ERROR_FILE_NOT_FOUND, FALSE },
- { "not_exist_dir\\not_exist_file", ERROR_PATH_NOT_FOUND, FALSE },
- { NULL, ERROR_PATH_NOT_FOUND, FALSE }
+ { "tr2_test_dir\\f1_symlink", ERROR_SUCCESS },
+ { "tr2_test_dir\\f1_link", ERROR_SUCCESS },
+ { "tr2_test_dir\\f1", ERROR_SUCCESS },
+ { "tr2_test_dir", ERROR_ACCESS_DENIED },
+ { "not_exist", ERROR_FILE_NOT_FOUND },
+ { "not_exist_dir\\not_exist_file", ERROR_PATH_NOT_FOUND },
+ { NULL, ERROR_PATH_NOT_FOUND }
};
GetCurrentDirectoryA(MAX_PATH, current_path);
@@ -2040,9 +2034,8 @@ static void test_tr2_sys__Unlink(void)
for(i=0; i<ARRAY_SIZE(tests); i++) {
errno = 0xdeadbeef;
ret = p_tr2_sys__Unlink(tests[i].path);
- todo_wine_if(tests[i].is_todo)
- ok(ret == tests[i].last_error, "tr2_sys__Unlink(): test %d expect: %d, got %d\n",
- i+1, tests[i].last_error, ret);
+ ok(ret == tests[i].last_error, "tr2_sys__Unlink(): test %d expect: %d, got %d\n",
+ i+1, tests[i].last_error, ret);
ok(errno == 0xdeadbeef, "tr2_sys__Unlink(): test %d errno expect: 0xdeadbeef, got %d\n", i+1, ret);
}
diff --git a/dlls/msvcp140/tests/msvcp140.c b/dlls/msvcp140/tests/msvcp140.c
index 04406240e0..46b2b8595d 100644
--- a/dlls/msvcp140/tests/msvcp140.c
+++ b/dlls/msvcp140/tests/msvcp140.c
@@ -802,16 +802,15 @@ static void test_Stat(void)
WCHAR const *path;
enum file_type ret;
int perms;
- int is_todo;
} tests[] = {
- { NULL, file_not_found, 0xdeadbeef, FALSE },
- { test_dirW, directory_file, 0777, FALSE },
- { test_f1W, regular_file, 0777, FALSE },
- { test_f2W, regular_file, 0555, FALSE },
- { test_neW, file_not_found, 0xdeadbeef, FALSE },
- { test_invW, file_not_found, 0xdeadbeef, FALSE },
- { test_f1_linkW, regular_file, 0777, TRUE },
- { test_dir_linkW, directory_file, 0777, TRUE },
+ { NULL, file_not_found, 0xdeadbeef },
+ { test_dirW, directory_file, 0777 },
+ { test_f1W, regular_file, 0777 },
+ { test_f2W, regular_file, 0555 },
+ { test_neW, file_not_found, 0xdeadbeef },
+ { test_invW, file_not_found, 0xdeadbeef },
+ { test_f1_linkW, regular_file, 0777 },
+ { test_dir_linkW, directory_file, 0777 },
};
GetCurrentDirectoryW(MAX_PATH, origin_path);
@@ -866,26 +865,20 @@ static void test_Stat(void)
for(i=0; i<ARRAY_SIZE(tests); i++) {
perms = 0xdeadbeef;
val = p_Stat(tests[i].path, &perms);
- todo_wine_if(tests[i].is_todo) {
- ok(tests[i].ret == val, "_Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
- ok(tests[i].perms == perms, "_Stat(): test %d perms expect: 0%o, got 0%o\n",
- i+1, tests[i].perms, perms);
- }
+ ok(tests[i].ret == val, "_Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
+ ok(tests[i].perms == perms, "_Stat(): test %d perms expect: 0%o, got 0%o\n",
+ i+1, tests[i].perms, perms);
val = p_Stat(tests[i].path, NULL);
- todo_wine_if(tests[i].is_todo)
- ok(tests[i].ret == val, "_Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
+ ok(tests[i].ret == val, "_Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
/* test _Lstat */
perms = 0xdeadbeef;
val = p_Lstat(tests[i].path, &perms);
- todo_wine_if(tests[i].is_todo) {
- ok(tests[i].ret == val, "_Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
- ok(tests[i].perms == perms, "_Lstat(): test %d perms expect: 0%o, got 0%o\n",
- i+1, tests[i].perms, perms);
- }
+ ok(tests[i].ret == val, "_Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
+ ok(tests[i].perms == perms, "_Lstat(): test %d perms expect: 0%o, got 0%o\n",
+ i+1, tests[i].perms, perms);
val = p_Lstat(tests[i].path, NULL);
- todo_wine_if(tests[i].is_todo)
- ok(tests[i].ret == val, "_Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
+ ok(tests[i].ret == val, "_Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
}
GetSystemDirectoryW(sys_path, MAX_PATH);
@@ -895,8 +888,8 @@ static void test_Stat(void)
ok(0777 == perms, "_Stat(): perms expect: 0777, got 0%o\n", perms);
if(ret) {
- todo_wine ok(DeleteFileW(test_f1_linkW), "expect wine_test_dir/f1_link to exist\n");
- todo_wine ok(RemoveDirectoryW(test_dir_linkW), "expect wine_test_dir/dir_link to exist\n");
+ ok(DeleteFileW(test_f1_linkW), "expect wine_test_dir/f1_link to exist\n");
+ ok(RemoveDirectoryW(test_dir_linkW), "expect wine_test_dir/dir_link to exist\n");
}
ok(DeleteFileW(test_f1W), "expect wine_test_dir/f1 to exist\n");
SetFileAttributesW(test_f2W, FILE_ATTRIBUTE_NORMAL);
@@ -1041,15 +1034,14 @@ static void test_Unlink(void)
struct {
WCHAR const *path;
int last_error;
- MSVCP_bool is_todo;
} tests[] = {
- { f1_symlinkW, ERROR_SUCCESS, TRUE },
- { f1_linkW, ERROR_SUCCESS, FALSE },
- { f1W, ERROR_SUCCESS, FALSE },
- { wine_test_dirW, ERROR_ACCESS_DENIED, FALSE },
- { not_existW, ERROR_FILE_NOT_FOUND, FALSE },
- { not_exist_fileW, ERROR_PATH_NOT_FOUND, FALSE },
- { NULL, ERROR_PATH_NOT_FOUND, FALSE }
+ { f1_symlinkW, ERROR_SUCCESS },
+ { f1_linkW, ERROR_SUCCESS },
+ { f1W, ERROR_SUCCESS },
+ { wine_test_dirW, ERROR_ACCESS_DENIED },
+ { not_existW, ERROR_FILE_NOT_FOUND },
+ { not_exist_fileW, ERROR_PATH_NOT_FOUND },
+ { NULL, ERROR_PATH_NOT_FOUND }
};
GetCurrentDirectoryW(MAX_PATH, current_path);
@@ -1078,9 +1070,8 @@ static void test_Unlink(void)
for(i=0; i<ARRAY_SIZE(tests); i++) {
errno = 0xdeadbeef;
ret = p_Unlink(tests[i].path);
- todo_wine_if(tests[i].is_todo)
- ok(ret == tests[i].last_error, "_Unlink(): test %d expect: %d, got %d\n",
- i+1, tests[i].last_error, ret);
+ ok(ret == tests[i].last_error, "_Unlink(): test %d expect: %d, got %d\n",
+ i+1, tests[i].last_error, ret);
ok(errno == 0xdeadbeef, "_Unlink(): test %d errno expect: 0xdeadbeef, got %d\n", i+1, ret);
}
--
2.17.1

View File

@ -3332,9 +3332,9 @@ fi
# | * [#12401] Support for Junction Points
# |
# | Modified files:
# | * configure.ac, dlls/kernel32/path.c, dlls/kernel32/tests/path.c, dlls/kernel32/volume.c, dlls/ntdll/file.c,
# | dlls/ntdll/tests/file.c, include/Makefile.in, include/ntifs.h, include/wine/port.h, libs/port/Makefile.in,
# | libs/port/renameat2.c, server/fd.c
# | * configure.ac, dlls/kernel32/path.c, dlls/kernel32/tests/path.c, dlls/kernel32/volume.c, dlls/msvcp120/tests/msvcp120.c,
# | dlls/msvcp140/tests/msvcp140.c, dlls/ntdll/directory.c, dlls/ntdll/file.c, dlls/ntdll/tests/file.c, include/Makefile.in,
# | include/ntifs.h, include/wine/port.h, include/winternl.h, libs/port/Makefile.in, libs/port/renameat2.c, server/fd.c
# |
if test "$enable_ntdll_Junction_Points" -eq 1; then
patch_apply ntdll-Junction_Points/0001-ntdll-Add-support-for-junction-point-creation.patch
@ -3349,10 +3349,14 @@ if test "$enable_ntdll_Junction_Points" -eq 1; then
patch_apply ntdll-Junction_Points/0010-ntdll-Add-support-for-relative-symlink-creation.patch
patch_apply ntdll-Junction_Points/0011-ntdll-Add-support-for-reading-relative-symlinks.patch
patch_apply ntdll-Junction_Points/0012-ntdll-Add-support-for-file-symlinks.patch
patch_apply ntdll-Junction_Points/0013-ntdll-Correctly-report-file-symbolic-links-as-files.patch
patch_apply ntdll-Junction_Points/0014-kernel32-Set-error-code-when-attempting-to-delete-fi.patch
patch_apply ntdll-Junction_Points/0015-server-Properly-handle-file-symlink-deletion.patch
patch_apply ntdll-Junction_Points/0016-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch
patch_apply ntdll-Junction_Points/0013-ntdll-Allow-creation-of-dangling-reparse-points-to-n.patch
patch_apply ntdll-Junction_Points/0014-ntdll-Correctly-report-file-symbolic-links-as-files.patch
patch_apply ntdll-Junction_Points/0015-ntdll-Correctly-report-fd-based-file-info-for-symlin.patch
patch_apply ntdll-Junction_Points/0016-kernel32-Set-error-code-when-attempting-to-delete-fi.patch
patch_apply ntdll-Junction_Points/0017-server-Properly-handle-file-symlink-deletion.patch
patch_apply ntdll-Junction_Points/0018-ntdll-Always-report-symbolic-links-as-containing-zer.patch
patch_apply ntdll-Junction_Points/0019-ntdll-Find-dangling-symlinks-quickly.patch
patch_apply ntdll-Junction_Points/0020-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch
(
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for junction point creation.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for reading junction points.", 1 },';
@ -3366,9 +3370,13 @@ if test "$enable_ntdll_Junction_Points" -eq 1; then
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for relative symlink creation.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for reading relative symlinks.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for file symlinks.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Allow creation of dangling reparse points to non-existent paths.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Correctly report file symbolic links as files.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Correctly report fd-based file info for symlinks.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "kernel32: Set error code when attempting to delete file symlinks as directories.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "server: Properly handle file symlink deletion.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Always report symbolic links as containing zero bytes.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Find dangling symlinks quickly.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "kernel32: Implement CreateSymbolicLink[A|W] with ntdll reparse points.", 1 },';
) >> "$patchlist"
fi

View File

@ -1,4 +1,4 @@
From 987c69eed0950c375af8eeb97dda539f9a636677 Mon Sep 17 00:00:00 2001
From feeebcd6395d58018766047dcf0d8debc0e3d97d Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Fri, 3 Apr 2015 03:58:47 +0200
Subject: [PATCH] server: Allow to open files without any permission bits. (try
@ -13,10 +13,10 @@ Changes in v2:
2 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
index 56251db..a5ab606 100644
index 7f27c79..9ebc40a 100644
--- a/dlls/advapi32/tests/security.c
+++ b/dlls/advapi32/tests/security.c
@@ -3718,17 +3718,13 @@ static void test_CreateDirectoryA(void)
@@ -3781,17 +3781,13 @@ static void test_CreateDirectoryA(void)
error = pGetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
(PSID *)&owner, NULL, &pDacl, NULL, &pSD);
@ -40,7 +40,7 @@ index 56251db..a5ab606 100644
CloseHandle(hTemp);
/* Test inheritance of ACLs in NtCreateFile without security descriptor */
@@ -3798,17 +3794,13 @@ static void test_CreateDirectoryA(void)
@@ -3861,17 +3857,13 @@ static void test_CreateDirectoryA(void)
error = pGetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
(PSID *)&owner, NULL, &pDacl, NULL, &pSD);
@ -65,10 +65,10 @@ index 56251db..a5ab606 100644
done:
diff --git a/server/fd.c b/server/fd.c
index ac046c9..770cc0d 100644
index 0ee86ef..da486b7 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1817,6 +1817,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
@@ -1824,6 +1824,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
struct fd *fd;
int root_fd = -1;
int rw_mode;
@ -76,10 +76,10 @@ index ac046c9..770cc0d 100644
int created = (flags & O_CREAT);
if (((options & FILE_DELETE_ON_CLOSE) && !(access & DELETE)) ||
@@ -1878,10 +1879,28 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
if ((access & FILE_UNIX_WRITE_ACCESS) || (flags & O_CREAT))
fd->unix_fd = open( name, O_RDONLY | (flags & ~(O_TRUNC | O_CREAT | O_EXCL)), *mode );
@@ -1892,10 +1893,28 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
fd->unix_fd = open( name, rw_mode | O_SYMLINK | (flags & ~O_TRUNC), *mode );
}
#endif
+ else if (errno == EACCES)
+ {
+ /* try to change permissions temporarily to open a file descriptor */
@ -105,7 +105,7 @@ index ac046c9..770cc0d 100644
goto error;
}
}
@@ -1889,6 +1908,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
@@ -1903,6 +1922,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
closed_fd->unix_fd = fd->unix_fd;
closed_fd->unlink = 0;
closed_fd->unix_name = fd->unix_name;