From 082a898ad4b267397cafaef1bcff0f86357f0cdf Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Fri, 10 May 2019 08:57:46 +1000 Subject: [PATCH] Updated ntdll-Junction_Points patchset --- ...retrieving-DOS-attributes-in-NtQuery.patch | 30 +- ...storing-DOS-attributes-in-NtSetInfor.patch | 29 +- ...-support-for-junction-point-creation.patch | 10 +- ...-support-for-reading-junction-points.patch | 2 +- ...support-for-deleting-junction-points.patch | 2 +- ...est-for-junction-point-advertisement.patch | 2 +- ...dd-support-for-deleting-junction-poi.patch | 2 +- ...l32-Advertise-junction-point-support.patch | 4 +- ...upport-for-absolute-symlink-creation.patch | 2 +- ...upport-for-reading-absolute-symlinks.patch | 2 +- ...ll-Add-support-for-deleting-symlinks.patch | 2 +- ...upport-for-relative-symlink-creation.patch | 2 +- ...upport-for-reading-relative-symlinks.patch | 2 +- ...-ntdll-Add-support-for-file-symlinks.patch | 6 +- ...tion-of-dangling-reparse-points-to-n.patch | 68 +++ ...report-file-symbolic-links-as-files.patch} | 35 +- ...report-fd-based-file-info-for-symlin.patch | 137 +++++ ...nt-CreateSymbolicLink-A-W-with-ntdll.patch | 288 ---------- ...r-code-when-attempting-to-delete-fi.patch} | 4 +- ...operly-handle-file-symlink-deletion.patch} | 43 +- ...ort-symbolic-links-as-containing-zer.patch | 93 +++ ...ntdll-Find-dangling-symlinks-quickly.patch | 47 ++ ...nt-CreateSymbolicLink-A-W-with-ntdll.patch | 542 ++++++++++++++++++ patches/patchinstall.sh | 22 +- ...open-files-without-any-permission-bi.patch | 20 +- 25 files changed, 1007 insertions(+), 389 deletions(-) create mode 100644 patches/ntdll-Junction_Points/0013-ntdll-Allow-creation-of-dangling-reparse-points-to-n.patch rename patches/ntdll-Junction_Points/{0013-ntdll-Correctly-report-file-symbolic-links-as-files.patch => 0014-ntdll-Correctly-report-file-symbolic-links-as-files.patch} (87%) create mode 100644 patches/ntdll-Junction_Points/0015-ntdll-Correctly-report-fd-based-file-info-for-symlin.patch delete mode 100644 patches/ntdll-Junction_Points/0016-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch rename patches/ntdll-Junction_Points/{0014-kernel32-Set-error-code-when-attempting-to-delete-fi.patch => 0016-kernel32-Set-error-code-when-attempting-to-delete-fi.patch} (95%) rename patches/ntdll-Junction_Points/{0015-server-Properly-handle-file-symlink-deletion.patch => 0017-server-Properly-handle-file-symlink-deletion.patch} (76%) create mode 100644 patches/ntdll-Junction_Points/0018-ntdll-Always-report-symbolic-links-as-containing-zer.patch create mode 100644 patches/ntdll-Junction_Points/0019-ntdll-Find-dangling-symlinks-quickly.patch create mode 100644 patches/ntdll-Junction_Points/0020-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch diff --git a/patches/ntdll-DOS_Attributes/0001-ntdll-Implement-retrieving-DOS-attributes-in-NtQuery.patch b/patches/ntdll-DOS_Attributes/0001-ntdll-Implement-retrieving-DOS-attributes-in-NtQuery.patch index 98696660..daf7d9eb 100644 --- a/patches/ntdll-DOS_Attributes/0001-ntdll-Implement-retrieving-DOS-attributes-in-NtQuery.patch +++ b/patches/ntdll-DOS_Attributes/0001-ntdll-Implement-retrieving-DOS-attributes-in-NtQuery.patch @@ -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" 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 #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 diff --git a/patches/ntdll-DOS_Attributes/0003-ntdll-Implement-storing-DOS-attributes-in-NtSetInfor.patch b/patches/ntdll-DOS_Attributes/0003-ntdll-Implement-storing-DOS-attributes-in-NtSetInfor.patch index 25dd8702..f094411e 100644 --- a/patches/ntdll-DOS_Attributes/0003-ntdll-Implement-storing-DOS-attributes-in-NtSetInfor.patch +++ b/patches/ntdll-DOS_Attributes/0003-ntdll-Implement-storing-DOS-attributes-in-NtSetInfor.patch @@ -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" 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 ); diff --git a/patches/ntdll-Junction_Points/0001-ntdll-Add-support-for-junction-point-creation.patch b/patches/ntdll-Junction_Points/0001-ntdll-Add-support-for-junction-point-creation.patch index e4dc862d..43376284 100644 --- a/patches/ntdll-Junction_Points/0001-ntdll-Add-support-for-junction-point-creation.patch +++ b/patches/ntdll-Junction_Points/0001-ntdll-Add-support-for-junction-point-creation.patch @@ -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" 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 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 \ diff --git a/patches/ntdll-Junction_Points/0002-ntdll-Add-support-for-reading-junction-points.patch b/patches/ntdll-Junction_Points/0002-ntdll-Add-support-for-reading-junction-points.patch index 4b873882..ecd3424e 100644 --- a/patches/ntdll-Junction_Points/0002-ntdll-Add-support-for-reading-junction-points.patch +++ b/patches/ntdll-Junction_Points/0002-ntdll-Add-support-for-reading-junction-points.patch @@ -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" Date: Thu, 16 Jan 2014 20:57:57 -0700 Subject: ntdll: Add support for reading junction points. diff --git a/patches/ntdll-Junction_Points/0003-ntdll-Add-support-for-deleting-junction-points.patch b/patches/ntdll-Junction_Points/0003-ntdll-Add-support-for-deleting-junction-points.patch index 9e39d5f8..199eb2c5 100644 --- a/patches/ntdll-Junction_Points/0003-ntdll-Add-support-for-deleting-junction-points.patch +++ b/patches/ntdll-Junction_Points/0003-ntdll-Add-support-for-deleting-junction-points.patch @@ -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" Date: Thu, 16 Jan 2014 21:00:21 -0700 Subject: ntdll: Add support for deleting junction points. diff --git a/patches/ntdll-Junction_Points/0004-ntdll-Add-a-test-for-junction-point-advertisement.patch b/patches/ntdll-Junction_Points/0004-ntdll-Add-a-test-for-junction-point-advertisement.patch index b71cff04..4d8fb013 100644 --- a/patches/ntdll-Junction_Points/0004-ntdll-Add-a-test-for-junction-point-advertisement.patch +++ b/patches/ntdll-Junction_Points/0004-ntdll-Add-a-test-for-junction-point-advertisement.patch @@ -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" Date: Thu, 16 Jan 2014 21:01:25 -0700 Subject: ntdll: Add a test for junction point advertisement. diff --git a/patches/ntdll-Junction_Points/0005-kernel32-ntdll-Add-support-for-deleting-junction-poi.patch b/patches/ntdll-Junction_Points/0005-kernel32-ntdll-Add-support-for-deleting-junction-poi.patch index e16101ff..c331e64e 100644 --- a/patches/ntdll-Junction_Points/0005-kernel32-ntdll-Add-support-for-deleting-junction-poi.patch +++ b/patches/ntdll-Junction_Points/0005-kernel32-ntdll-Add-support-for-deleting-junction-poi.patch @@ -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" Date: Thu, 16 Jan 2014 21:02:11 -0700 Subject: kernel32,ntdll: Add support for deleting junction points with diff --git a/patches/ntdll-Junction_Points/0006-kernel32-Advertise-junction-point-support.patch b/patches/ntdll-Junction_Points/0006-kernel32-Advertise-junction-point-support.patch index ab5eb977..d5be7382 100644 --- a/patches/ntdll-Junction_Points/0006-kernel32-Advertise-junction-point-support.patch +++ b/patches/ntdll-Junction_Points/0006-kernel32-Advertise-junction-point-support.patch @@ -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" 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 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 @@ diff --git a/patches/ntdll-Junction_Points/0007-ntdll-Add-support-for-absolute-symlink-creation.patch b/patches/ntdll-Junction_Points/0007-ntdll-Add-support-for-absolute-symlink-creation.patch index 524113db..032605c3 100644 --- a/patches/ntdll-Junction_Points/0007-ntdll-Add-support-for-absolute-symlink-creation.patch +++ b/patches/ntdll-Junction_Points/0007-ntdll-Add-support-for-absolute-symlink-creation.patch @@ -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" Date: Thu, 16 Jan 2014 21:06:24 -0700 Subject: ntdll: Add support for absolute symlink creation. diff --git a/patches/ntdll-Junction_Points/0008-ntdll-Add-support-for-reading-absolute-symlinks.patch b/patches/ntdll-Junction_Points/0008-ntdll-Add-support-for-reading-absolute-symlinks.patch index 2403c11b..5babe32d 100644 --- a/patches/ntdll-Junction_Points/0008-ntdll-Add-support-for-reading-absolute-symlinks.patch +++ b/patches/ntdll-Junction_Points/0008-ntdll-Add-support-for-reading-absolute-symlinks.patch @@ -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" Date: Wed, 13 Mar 2019 12:55:20 -0600 Subject: ntdll: Add support for reading absolute symlinks. diff --git a/patches/ntdll-Junction_Points/0009-ntdll-Add-support-for-deleting-symlinks.patch b/patches/ntdll-Junction_Points/0009-ntdll-Add-support-for-deleting-symlinks.patch index e653b8a6..d441d74c 100644 --- a/patches/ntdll-Junction_Points/0009-ntdll-Add-support-for-deleting-symlinks.patch +++ b/patches/ntdll-Junction_Points/0009-ntdll-Add-support-for-deleting-symlinks.patch @@ -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" Date: Wed, 13 Mar 2019 13:02:22 -0600 Subject: ntdll: Add support for deleting symlinks. diff --git a/patches/ntdll-Junction_Points/0010-ntdll-Add-support-for-relative-symlink-creation.patch b/patches/ntdll-Junction_Points/0010-ntdll-Add-support-for-relative-symlink-creation.patch index 2c9a0ac8..cddf356e 100644 --- a/patches/ntdll-Junction_Points/0010-ntdll-Add-support-for-relative-symlink-creation.patch +++ b/patches/ntdll-Junction_Points/0010-ntdll-Add-support-for-relative-symlink-creation.patch @@ -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" Date: Thu, 11 Apr 2019 12:16:49 -0600 Subject: ntdll: Add support for relative symlink creation. diff --git a/patches/ntdll-Junction_Points/0011-ntdll-Add-support-for-reading-relative-symlinks.patch b/patches/ntdll-Junction_Points/0011-ntdll-Add-support-for-reading-relative-symlinks.patch index defd790c..ba973651 100644 --- a/patches/ntdll-Junction_Points/0011-ntdll-Add-support-for-reading-relative-symlinks.patch +++ b/patches/ntdll-Junction_Points/0011-ntdll-Add-support-for-reading-relative-symlinks.patch @@ -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" Date: Thu, 11 Apr 2019 12:31:16 -0600 Subject: ntdll: Add support for reading relative symlinks. diff --git a/patches/ntdll-Junction_Points/0012-ntdll-Add-support-for-file-symlinks.patch b/patches/ntdll-Junction_Points/0012-ntdll-Add-support-for-file-symlinks.patch index a719b4d5..869d1689 100644 --- a/patches/ntdll-Junction_Points/0012-ntdll-Add-support-for-file-symlinks.patch +++ b/patches/ntdll-Junction_Points/0012-ntdll-Add-support-for-file-symlinks.patch @@ -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" 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); diff --git a/patches/ntdll-Junction_Points/0013-ntdll-Allow-creation-of-dangling-reparse-points-to-n.patch b/patches/ntdll-Junction_Points/0013-ntdll-Allow-creation-of-dangling-reparse-points-to-n.patch new file mode 100644 index 00000000..c1fb1d80 --- /dev/null +++ b/patches/ntdll-Junction_Points/0013-ntdll-Allow-creation-of-dangling-reparse-points-to-n.patch @@ -0,0 +1,68 @@ +From 1cb09e87cf0fd0a805849f3483d2b3b7bed5ec18 Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +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 +--- + 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 + diff --git a/patches/ntdll-Junction_Points/0013-ntdll-Correctly-report-file-symbolic-links-as-files.patch b/patches/ntdll-Junction_Points/0014-ntdll-Correctly-report-file-symbolic-links-as-files.patch similarity index 87% rename from patches/ntdll-Junction_Points/0013-ntdll-Correctly-report-file-symbolic-links-as-files.patch rename to patches/ntdll-Junction_Points/0014-ntdll-Correctly-report-file-symbolic-links-as-files.patch index 47a44009..091dd3fb 100644 --- a/patches/ntdll-Junction_Points/0013-ntdll-Correctly-report-file-symbolic-links-as-files.patch +++ b/patches/ntdll-Junction_Points/0014-ntdll-Correctly-report-file-symbolic-links-as-files.patch @@ -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" Date: Sat, 30 Mar 2019 12:00:51 -0600 Subject: ntdll: Correctly report file symbolic links as files. Signed-off-by: Erich E. Hoover --- - 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) diff --git a/patches/ntdll-Junction_Points/0015-ntdll-Correctly-report-fd-based-file-info-for-symlin.patch b/patches/ntdll-Junction_Points/0015-ntdll-Correctly-report-fd-based-file-info-for-symlin.patch new file mode 100644 index 00000000..950c11bd --- /dev/null +++ b/patches/ntdll-Junction_Points/0015-ntdll-Correctly-report-fd-based-file-info-for-symlin.patch @@ -0,0 +1,137 @@ +From 4f8611e2dfc7fb70e13a6f05949257e5d441328a Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +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 +--- + 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 + diff --git a/patches/ntdll-Junction_Points/0016-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch b/patches/ntdll-Junction_Points/0016-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch deleted file mode 100644 index 660bfcaa..00000000 --- a/patches/ntdll-Junction_Points/0016-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch +++ /dev/null @@ -1,288 +0,0 @@ -From 99b54adfcc2740af27224957748f94a0e84b47c3 Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -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 ---- - 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 - diff --git a/patches/ntdll-Junction_Points/0014-kernel32-Set-error-code-when-attempting-to-delete-fi.patch b/patches/ntdll-Junction_Points/0016-kernel32-Set-error-code-when-attempting-to-delete-fi.patch similarity index 95% rename from patches/ntdll-Junction_Points/0014-kernel32-Set-error-code-when-attempting-to-delete-fi.patch rename to patches/ntdll-Junction_Points/0016-kernel32-Set-error-code-when-attempting-to-delete-fi.patch index 76301c98..d053bdcc 100644 --- a/patches/ntdll-Junction_Points/0014-kernel32-Set-error-code-when-attempting-to-delete-fi.patch +++ b/patches/ntdll-Junction_Points/0016-kernel32-Set-error-code-when-attempting-to-delete-fi.patch @@ -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" 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) diff --git a/patches/ntdll-Junction_Points/0015-server-Properly-handle-file-symlink-deletion.patch b/patches/ntdll-Junction_Points/0017-server-Properly-handle-file-symlink-deletion.patch similarity index 76% rename from patches/ntdll-Junction_Points/0015-server-Properly-handle-file-symlink-deletion.patch rename to patches/ntdll-Junction_Points/0017-server-Properly-handle-file-symlink-deletion.patch index 464afc5a..ba63f84e 100644 --- a/patches/ntdll-Junction_Points/0015-server-Properly-handle-file-symlink-deletion.patch +++ b/patches/ntdll-Junction_Points/0017-server-Properly-handle-file-symlink-deletion.patch @@ -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" 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 --- 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 + # 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; diff --git a/patches/ntdll-Junction_Points/0018-ntdll-Always-report-symbolic-links-as-containing-zer.patch b/patches/ntdll-Junction_Points/0018-ntdll-Always-report-symbolic-links-as-containing-zer.patch new file mode 100644 index 00000000..9200db25 --- /dev/null +++ b/patches/ntdll-Junction_Points/0018-ntdll-Always-report-symbolic-links-as-containing-zer.patch @@ -0,0 +1,93 @@ +From 5eb8e81e70075947729f70e59825d472db8faf2a Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +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 +--- + 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 + diff --git a/patches/ntdll-Junction_Points/0019-ntdll-Find-dangling-symlinks-quickly.patch b/patches/ntdll-Junction_Points/0019-ntdll-Find-dangling-symlinks-quickly.patch new file mode 100644 index 00000000..5a4ea976 --- /dev/null +++ b/patches/ntdll-Junction_Points/0019-ntdll-Find-dangling-symlinks-quickly.patch @@ -0,0 +1,47 @@ +From e573ccae4f2584e7f7c040f1c1f986d1e7ebdc6e Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +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 +--- + 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 + diff --git a/patches/ntdll-Junction_Points/0020-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch b/patches/ntdll-Junction_Points/0020-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch new file mode 100644 index 00000000..5a90c4b1 --- /dev/null +++ b/patches/ntdll-Junction_Points/0020-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch @@ -0,0 +1,542 @@ +From 3b19992c3906902dfb452360c0e0b22d31ab0a6e Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +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 +--- + 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> "$patchlist" fi diff --git a/patches/server-File_Permissions/0002-server-Allow-to-open-files-without-any-permission-bi.patch b/patches/server-File_Permissions/0002-server-Allow-to-open-files-without-any-permission-bi.patch index 114ee306..ae49791d 100644 --- a/patches/server-File_Permissions/0002-server-Allow-to-open-files-without-any-permission-bi.patch +++ b/patches/server-File_Permissions/0002-server-Allow-to-open-files-without-any-permission-bi.patch @@ -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 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;