diff --git a/debian/changelog b/debian/changelog index e8a0aac3..80c05fe0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -22,6 +22,7 @@ wine-staging (1.7.40) UNRELEASED; urgency=low * Removed patch to emulate 'mov Eb, Gb' instruction on x86 processor architecture (accepted upstream). * Removed patches for Setup*Log() functions (accepted upstream). * Removed tests for job objects (accepted upstream). + * Partially removed patches for job objects (accepted upstream). -- Sebastian Lackner Mon, 23 Mar 2015 16:12:20 +0100 wine-staging (1.7.39) unstable; urgency=low diff --git a/patches/advapi32-Revert_DACL/0004-Revert-server-Make-directory-DACL-entries-inheritabl.patch b/patches/advapi32-Revert_DACL/0004-Revert-server-Make-directory-DACL-entries-inheritabl.patch index 34f3acad..1cb6b26f 100644 --- a/patches/advapi32-Revert_DACL/0004-Revert-server-Make-directory-DACL-entries-inheritabl.patch +++ b/patches/advapi32-Revert_DACL/0004-Revert-server-Make-directory-DACL-entries-inheritabl.patch @@ -1,46 +1,29 @@ -From e2eaeb0bfc7411c74f1387e59c121f5cee6c013a Mon Sep 17 00:00:00 2001 +From 41ffec5994a45a7f18cd77e98d8cf7bedecfd9a4 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Fri, 27 Mar 2015 15:32:44 +0100 Subject: Revert "server: Make directory DACL entries inheritable." This reverts commit 3eb448cf33b6b6635bac4e06ea7fddd190e26450. --- - dlls/advapi32/tests/security.c | 12 ++++++------ - server/file.c | 8 ++++---- - 2 files changed, 10 insertions(+), 10 deletions(-) + dlls/advapi32/tests/security.c | 2 +- + server/file.c | 8 ++++---- + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c -index e3c1659..04a88ae 100644 +index b19dbe8..a757c22 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c -@@ -3192,9 +3192,9 @@ static void test_CreateDirectoryA(void) - ok(bret, "Failed to get Current User ACE.\n"); - bret = EqualSid(&ace->SidStart, user_sid); - todo_wine ok(bret, "Current User ACE != Current User SID.\n"); -- ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE), -- "Current User ACE has unexpected flags (0x%x != 0x03)\n", -- ((ACE_HEADER *)ace)->AceFlags); -+ todo_wine ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE), -+ "Current User ACE has unexpected flags (0x%x != 0x03)\n", -+ ((ACE_HEADER *)ace)->AceFlags); - ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n", - ace->Mask); - } -@@ -3204,9 +3204,9 @@ static void test_CreateDirectoryA(void) - ok(bret, "Failed to get Administators Group ACE.\n"); - bret = EqualSid(&ace->SidStart, admin_sid); - todo_wine ok(bret, "Administators Group ACE != Administators Group SID.\n"); -- ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE), -- "Administators Group ACE has unexpected flags (0x%x != 0x03)\n", -- ((ACE_HEADER *)ace)->AceFlags); -+ todo_wine ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE), -+ "Administators Group ACE has unexpected flags (0x%x != 0x03)\n", -+ ((ACE_HEADER *)ace)->AceFlags); - ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n", - ace->Mask); +@@ -3262,7 +3262,7 @@ static void test_CreateDirectoryA(void) } + ok(!error, "GetNamedSecurityInfo failed with error %d\n", error); + test_inherited_dacl(pDacl, admin_sid, user_sid, OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE, +- 0x1f01ff, FALSE, TRUE, FALSE, __LINE__); ++ 0x1f01ff, FALSE, TRUE, TRUE, __LINE__); + LocalFree(pSD); + + /* Test inheritance of ACLs in CreateFile without security descriptor */ diff --git a/server/file.c b/server/file.c -index f565f5a..abda2c3 100644 +index aa5ff01..c8c880b 100644 --- a/server/file.c +++ b/server/file.c @@ -367,7 +367,7 @@ struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 90be6428..3d8f644a 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -3873,20 +3873,18 @@ fi # | server/object.h, server/process.c, server/process.h, server/protocol.def # | if test "$enable_server_JobObjects" -eq 1; then - patch_apply server-JobObjects/0001-server-Basic-implementation-of-job-objects.-rev-2.patch + patch_apply server-JobObjects/0001-server-Implement-remaining-wineserver-calls-for-job-.patch patch_apply server-JobObjects/0002-server-Implement-completion-messages-for-job-objects.patch patch_apply server-JobObjects/0003-server-Properly-track-handle-count-of-objects.patch patch_apply server-JobObjects/0004-server-Implement-JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE.patch - patch_apply server-JobObjects/0005-server-Support-NULL-job-handles-in-IsProcessInJob.patch - patch_apply server-JobObjects/0006-kernel32-tests-Add-tests-for-waiting-on-an-job-objec.patch - patch_apply server-JobObjects/0007-server-Implement-waiting-for-job-objects.patch - patch_apply server-JobObjects/0008-ntdll-Implement-NtQueryInformationJobObject-stub-fun.patch + patch_apply server-JobObjects/0005-kernel32-tests-Add-tests-for-waiting-on-an-job-objec.patch + patch_apply server-JobObjects/0006-server-Implement-waiting-for-job-objects.patch + patch_apply server-JobObjects/0007-ntdll-Implement-NtQueryInformationJobObject-stub-fun.patch ( - echo '+ { "Andrew Cook", "server: Basic implementation of job objects.", 2 },'; + echo '+ { "Andrew Cook", "server: Implement remaining wineserver calls for job objects.", 1 },'; echo '+ { "Andrew Cook", "server: Implement completion messages for job objects.", 1 },'; echo '+ { "Andrew Cook", "server: Properly track handle count of objects.", 1 },'; echo '+ { "Andrew Cook", "server: Implement JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE.", 1 },'; - echo '+ { "Andrew Cook", "server: Support NULL job handles in IsProcessInJob.", 1 },'; echo '+ { "Sebastian Lackner", "kernel32/tests: Add tests for waiting on an job object.", 1 },'; echo '+ { "Sebastian Lackner", "server: Implement waiting for job objects.", 1 },'; echo '+ { "Sebastian Lackner", "ntdll: Implement NtQueryInformationJobObject stub function.", 1 },'; diff --git a/patches/server-Inherited_ACLs/0001-server-Inherit-security-attributes-from-parent-direc.patch b/patches/server-Inherited_ACLs/0001-server-Inherit-security-attributes-from-parent-direc.patch index e0f94c7f..a59151db 100644 --- a/patches/server-Inherited_ACLs/0001-server-Inherit-security-attributes-from-parent-direc.patch +++ b/patches/server-Inherited_ACLs/0001-server-Inherit-security-attributes-from-parent-direc.patch @@ -1,74 +1,36 @@ -From 7c47d281a127ddb60ac73cdc373afb3f2a27e2cd Mon Sep 17 00:00:00 2001 +From 2e6b68d04f4b74591fdbea0ef5fbea4879235c96 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Fri, 18 Apr 2014 14:08:36 -0600 Subject: server: Inherit security attributes from parent directories on creation. (try 7) --- - dlls/advapi32/tests/security.c | 10 --- + dlls/advapi32/tests/security.c | 4 +- server/file.c | 137 +++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 137 insertions(+), 10 deletions(-) + 2 files changed, 139 insertions(+), 2 deletions(-) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c -index 5209c13..e78e5f6 100644 +index a530a3f..ae9ec99 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c -@@ -3234,7 +3234,6 @@ static void test_CreateDirectoryA(void) +@@ -3278,7 +3278,7 @@ static void test_CreateDirectoryA(void) + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "Failed to get permissions on file\n"); + test_inherited_dacl(pDacl, admin_sid, user_sid, INHERITED_ACE, +- 0x1f01ff, TRUE, TRUE, TRUE, __LINE__); ++ 0x1f01ff, FALSE, FALSE, FALSE, __LINE__); + LocalFree(pSD); + CloseHandle(hTemp); - bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); - ok(bret, "GetAclInformation failed\n"); -- todo_wine - ok(acl_size.AceCount == 2, "GetAclInformation returned unexpected entry count (%d != 2).\n", - acl_size.AceCount); - if (acl_size.AceCount > 0) -@@ -3242,9 +3241,7 @@ static void test_CreateDirectoryA(void) - bret = pGetAce(pDacl, 0, (VOID **)&ace); - ok(bret, "Inherited Failed to get Current User ACE.\n"); - bret = EqualSid(&ace->SidStart, user_sid); -- todo_wine - ok(bret, "Inherited Current User ACE != Current User SID.\n"); -- todo_wine - ok(((ACE_HEADER *)ace)->AceFlags == INHERITED_ACE, - "Inherited Current User ACE has unexpected flags (0x%x != 0x10)\n", ((ACE_HEADER *)ace)->AceFlags); - ok(ace->Mask == 0x1f01ff, -@@ -3255,9 +3252,7 @@ static void test_CreateDirectoryA(void) - bret = pGetAce(pDacl, 1, (VOID **)&ace); - ok(bret, "Inherited Failed to get Administators Group ACE.\n"); - bret = EqualSid(&ace->SidStart, admin_sid); -- todo_wine - ok(bret, "Inherited Administators Group ACE != Administators Group SID.\n"); -- todo_wine - ok(((ACE_HEADER *)ace)->AceFlags == INHERITED_ACE, - "Inherited Administators Group ACE has unexpected flags (0x%x != 0x10)\n", ((ACE_HEADER *)ace)->AceFlags); - ok(ace->Mask == 0x1f01ff, -@@ -3290,7 +3285,6 @@ static void test_CreateDirectoryA(void) +@@ -3352,7 +3352,7 @@ static void test_CreateDirectoryA(void) + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "Failed to get permissions on file\n"); + test_inherited_dacl(pDacl, admin_sid, user_sid, INHERITED_ACE, +- 0x1f01ff, TRUE, TRUE, TRUE, __LINE__); ++ 0x1f01ff, FALSE, FALSE, FALSE, __LINE__); + LocalFree(pSD); + CloseHandle(hTemp); - bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); - ok(bret, "GetAclInformation failed\n"); -- todo_wine - ok(acl_size.AceCount == 2, "GetAclInformation returned unexpected entry count (%d != 2).\n", - acl_size.AceCount); - if (acl_size.AceCount > 0) -@@ -3298,9 +3292,7 @@ static void test_CreateDirectoryA(void) - bret = pGetAce(pDacl, 0, (VOID **)&ace); - ok(bret, "Inherited Failed to get Current User ACE.\n"); - bret = EqualSid(&ace->SidStart, user_sid); -- todo_wine - ok(bret, "Inherited Current User ACE != Current User SID.\n"); -- todo_wine - ok(((ACE_HEADER *)ace)->AceFlags == INHERITED_ACE, - "Inherited Current User ACE has unexpected flags (0x%x != 0x10)\n", ((ACE_HEADER *)ace)->AceFlags); - ok(ace->Mask == 0x1f01ff, -@@ -3311,9 +3303,7 @@ static void test_CreateDirectoryA(void) - bret = pGetAce(pDacl, 1, (VOID **)&ace); - ok(bret, "Inherited Failed to get Administators Group ACE.\n"); - bret = EqualSid(&ace->SidStart, admin_sid); -- todo_wine - ok(bret, "Inherited Administators Group ACE != Administators Group SID.\n"); -- todo_wine - ok(((ACE_HEADER *)ace)->AceFlags == INHERITED_ACE, - "Inherited Administators Group ACE has unexpected flags (0x%x != 0x10)\n", ((ACE_HEADER *)ace)->AceFlags); - ok(ace->Mask == 0x1f01ff, diff --git a/server/file.c b/server/file.c index b6435d1..43be63b 100644 --- a/server/file.c diff --git a/patches/server-JobObjects/0001-server-Basic-implementation-of-job-objects.-rev-2.patch b/patches/server-JobObjects/0001-server-Basic-implementation-of-job-objects.-rev-2.patch deleted file mode 100644 index 9865b600..00000000 --- a/patches/server-JobObjects/0001-server-Basic-implementation-of-job-objects.-rev-2.patch +++ /dev/null @@ -1,680 +0,0 @@ -From fdec43a9ec165284f52d8ecd734abd6e2fe93d90 Mon Sep 17 00:00:00 2001 -From: Andrew Cook -Date: Thu, 26 Feb 2015 12:25:23 +1100 -Subject: server: Basic implementation of job objects. (rev 2) - -This patch includes a (hopefully) complete implementation of process -tracking in job objects, but no limits or events outside of those. - -This does not implement nested jobs as found in windows 8. - -Changes by Sebastian Lackner : -* Only use a single list instead of two for active / all processes. -* Various cleanups to fit with the rest of the wineserver coding style. - -Changes in revision 2: -* Fix a wineserver crash when terminated processes are added to a job. ---- - dlls/kernel32/tests/process.c | 10 +- - dlls/ntdll/sync.c | 139 ++++++++++++++++++++--- - include/winnt.h | 4 + - server/process.c | 259 ++++++++++++++++++++++++++++++++++++++++++ - server/process.h | 3 + - server/protocol.def | 27 +++++ - 6 files changed, 420 insertions(+), 22 deletions(-) - -diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c -index 15ebd6e..6c2f86d 100644 ---- a/dlls/kernel32/tests/process.c -+++ b/dlls/kernel32/tests/process.c -@@ -2209,7 +2209,6 @@ static void test_IsProcessInJob(void) - out = FALSE; - ret = pIsProcessInJob(pi.hProcess, job, &out); - ok(ret, "IsProcessInJob error %u\n", GetLastError()); -- todo_wine - ok(out, "IsProcessInJob returned out=%u\n", out); - - TerminateProcess(pi.hProcess, 0); -@@ -2220,7 +2219,6 @@ static void test_IsProcessInJob(void) - out = FALSE; - ret = pIsProcessInJob(pi.hProcess, job, &out); - ok(ret, "IsProcessInJob error %u\n", GetLastError()); -- todo_wine - ok(out, "IsProcessInJob returned out=%u\n", out); - - CloseHandle(pi.hProcess); -@@ -2247,13 +2245,11 @@ static void test_TerminateJobObject(void) - ok(ret, "TerminateJobObject error %u\n", GetLastError()); - - dwret = WaitForSingleObject(pi.hProcess, 1000); -- todo_wine - ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); - if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0); - - ret = GetExitCodeProcess(pi.hProcess, &dwret); - ok(ret, "GetExitCodeProcess error %u\n", GetLastError()); -- todo_wine - ok(dwret == 123 || broken(dwret == 0) /* randomly fails on Win 2000 / XP */, - "wrong exitcode %u\n", dwret); - -@@ -2268,9 +2264,7 @@ static void test_TerminateJobObject(void) - - SetLastError(0xdeadbeef); - ret = pAssignProcessToJobObject(job, pi.hProcess); -- todo_wine - ok(!ret, "AssignProcessToJobObject unexpectedly succeeded\n"); -- todo_wine - expect_eq_d(ERROR_ACCESS_DENIED, GetLastError()); - - CloseHandle(pi.hProcess); -@@ -2381,6 +2375,7 @@ static void test_CompletionPort(void) - port_info.CompletionKey = job; - port_info.CompletionPort = port; - ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info)); -+ todo_wine - ok(ret, "SetInformationJobObject error %u\n", GetLastError()); - - create_process("wait", &pi); -@@ -2478,7 +2473,6 @@ static void test_jobInheritance(HANDLE job) - out = FALSE; - ret = pIsProcessInJob(pi.hProcess, job, &out); - ok(ret, "IsProcessInJob error %u\n", GetLastError()); -- todo_wine - ok(out, "IsProcessInJob returned out=%u\n", out); - - dwret = WaitForSingleObject(pi.hProcess, 1000); -@@ -2506,9 +2500,7 @@ static void test_BreakawayOk(HANDLE job) - snprintf(buffer, MAX_PATH, "\"%s\" tests/process.c %s", selfname, "exit"); - - ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi); -- todo_wine - ok(!ret, "CreateProcessA expected failure\n"); -- todo_wine - expect_eq_d(ERROR_ACCESS_DENIED, GetLastError()); - - if (ret) -diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c -index 7d44e60..a0b8c15 100644 ---- a/dlls/ntdll/sync.c -+++ b/dlls/ntdll/sync.c -@@ -56,6 +56,7 @@ - #include "wine/server.h" - #include "wine/debug.h" - #include "ntdll_misc.h" -+#include "winnt.h" - - WINE_DEFAULT_DEBUG_CHANNEL(ntdll); - -@@ -565,9 +566,36 @@ NTSTATUS WINAPI NtQueryMutant(IN HANDLE handle, - */ - NTSTATUS WINAPI NtCreateJobObject( PHANDLE handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) - { -- FIXME( "stub: %p %x %s\n", handle, access, attr ? debugstr_us(attr->ObjectName) : "" ); -- *handle = (HANDLE)0xdead; -- return STATUS_SUCCESS; -+ DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0; -+ NTSTATUS ret; -+ struct security_descriptor *sd = NULL; -+ struct object_attributes objattr; -+ -+ if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG; -+ -+ objattr.rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 ); -+ objattr.sd_len = 0; -+ objattr.name_len = len; -+ if (attr) -+ { -+ ret = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len ); -+ if (ret != STATUS_SUCCESS) return ret; -+ } -+ -+ SERVER_START_REQ( create_job ) -+ { -+ req->access = access; -+ req->attributes = attr ? attr->Attributes : 0; -+ wine_server_add_data( req, &objattr, sizeof(objattr) ); -+ if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len ); -+ if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len ); -+ ret = wine_server_call( req ); -+ *handle = wine_server_ptr_handle( reply->handle ); -+ } -+ SERVER_END_REQ; -+ -+ NTDLL_free_struct_sd( sd ); -+ return ret; - } - - /****************************************************************************** -@@ -586,8 +614,19 @@ NTSTATUS WINAPI NtOpenJobObject( PHANDLE handle, ACCESS_MASK access, const OBJEC - */ - NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status ) - { -- FIXME( "stub: %p %x\n", handle, status ); -- return STATUS_SUCCESS; -+ NTSTATUS ret; -+ -+ TRACE( "(%p, %d)\n", handle, status ); -+ -+ SERVER_START_REQ( terminate_job ) -+ { -+ req->handle = wine_server_obj_handle( handle ); -+ req->status = status; -+ ret = wine_server_call( req ); -+ } -+ SERVER_END_REQ; -+ -+ return ret; - } - - /****************************************************************************** -@@ -597,8 +636,17 @@ NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status ) - NTSTATUS WINAPI NtQueryInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info, - ULONG len, PULONG ret_len ) - { -- FIXME( "stub: %p %u %p %u %p\n", handle, class, info, len, ret_len ); -- return STATUS_NOT_IMPLEMENTED; -+ TRACE( "%p %u %p %u %p\n", handle, class, info, len, ret_len ); -+ -+ if (class >= MaxJobObjectInfoClass) -+ return STATUS_INVALID_PARAMETER; -+ -+ switch (class) -+ { -+ default: -+ FIXME( "stub: %p %u %p %u %p\n", handle, class, info, len, ret_len ); -+ return STATUS_NOT_IMPLEMENTED; -+ } - } - - /****************************************************************************** -@@ -607,8 +655,51 @@ NTSTATUS WINAPI NtQueryInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS c - */ - NTSTATUS WINAPI NtSetInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info, ULONG len ) - { -- FIXME( "stub: %p %u %p %u\n", handle, class, info, len ); -- return STATUS_SUCCESS; -+ JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit; -+ NTSTATUS status = STATUS_SUCCESS; -+ -+ TRACE( "(%p, %u, %p, %u)\n", handle, class, info, len ); -+ -+ if (class >= MaxJobObjectInfoClass) -+ return STATUS_INVALID_PARAMETER; -+ -+ switch (class) -+ { -+ -+ case JobObjectExtendedLimitInformation: -+ if (len != sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)) -+ return STATUS_INVALID_PARAMETER; -+ -+ basic_limit = &(((JOBOBJECT_EXTENDED_LIMIT_INFORMATION *)info)->BasicLimitInformation); -+ if (basic_limit->LimitFlags & ~JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS) -+ return STATUS_INVALID_PARAMETER; -+ -+ goto set_basic_limits; -+ -+ case JobObjectBasicLimitInformation: -+ if (len != sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION)) -+ return STATUS_INVALID_PARAMETER; -+ -+ basic_limit = info; -+ if (basic_limit->LimitFlags & ~JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS) -+ return STATUS_INVALID_PARAMETER; -+ -+ set_basic_limits: -+ SERVER_START_REQ( job_set_limits ) -+ { -+ req->handle = wine_server_obj_handle( handle ); -+ req->limit_flags = basic_limit->LimitFlags; -+ status = wine_server_call( req ); -+ } -+ SERVER_END_REQ; -+ break; -+ -+ default: -+ FIXME( "stub: %p %u %p %u\n", handle, class, info, len ); -+ return STATUS_NOT_IMPLEMENTED; -+ } -+ -+ return status; - } - - /****************************************************************************** -@@ -617,8 +708,19 @@ NTSTATUS WINAPI NtSetInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS cla - */ - NTSTATUS WINAPI NtIsProcessInJob( HANDLE process, HANDLE job ) - { -- FIXME( "stub: %p %p\n", process, job ); -- return STATUS_PROCESS_NOT_IN_JOB; -+ NTSTATUS status; -+ -+ TRACE( "(%p %p)\n", job, process ); -+ -+ SERVER_START_REQ( process_in_job ) -+ { -+ req->process_handle = wine_server_obj_handle( process ); -+ req->job_handle = wine_server_obj_handle( job ); -+ status = wine_server_call( req ); -+ } -+ SERVER_END_REQ; -+ -+ return status; - } - - /****************************************************************************** -@@ -627,8 +729,19 @@ NTSTATUS WINAPI NtIsProcessInJob( HANDLE process, HANDLE job ) - */ - NTSTATUS WINAPI NtAssignProcessToJobObject( HANDLE job, HANDLE process ) - { -- FIXME( "stub: %p %p\n", job, process ); -- return STATUS_SUCCESS; -+ NTSTATUS status; -+ -+ TRACE( "(%p %p)\n", job, process ); -+ -+ SERVER_START_REQ( job_assign ) -+ { -+ req->job_handle = wine_server_obj_handle( job ); -+ req->process_handle = wine_server_obj_handle( process ); -+ status = wine_server_call( req ); -+ } -+ SERVER_END_REQ; -+ -+ return status; - } - - /* -diff --git a/include/winnt.h b/include/winnt.h -index 4b06b2c..c2aa50e 100644 ---- a/include/winnt.h -+++ b/include/winnt.h -@@ -5610,6 +5610,10 @@ typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION { - #define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 - #define JOB_OBJECT_LIMIT_SUBSET_AFFINITY 0x00004000 - -+#define JOB_OBJECT_LIMIT_VALID_FLAGS 0x0007ffff -+#define JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS 0x000000ff -+#define JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS 0x00007fff -+ - typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP - { - RelationProcessorCore = 0, -diff --git a/server/process.c b/server/process.c -index 0712a5b..6384203 100644 ---- a/server/process.c -+++ b/server/process.c -@@ -65,6 +65,7 @@ static unsigned int process_map_access( struct object *obj, unsigned int access - static struct security_descriptor *process_get_sd( struct object *obj ); - static void process_poll_event( struct fd *fd, int event ); - static void process_destroy( struct object *obj ); -+static void terminate_process( struct process *process, struct thread *skip, int exit_code ); - - static const struct object_ops process_ops = - { -@@ -134,6 +135,157 @@ static const struct object_ops startup_info_ops = - startup_info_destroy /* destroy */ - }; - -+/* job object */ -+ -+static void job_dump( struct object *obj, int verbose ); -+static struct object_type *job_get_type( struct object *obj ); -+static int job_signaled( struct object *obj, struct wait_queue_entry *entry ); -+static unsigned int job_map_access( struct object *obj, unsigned int access ); -+static void job_destroy( struct object *obj ); -+ -+struct job -+{ -+ struct object obj; /* object header */ -+ struct list process_list; /* list of all processes */ -+ int num_processes; /* count of running processes */ -+ int limit_flags; /* limit flags */ -+}; -+ -+static const struct object_ops job_ops = -+{ -+ sizeof(struct job), /* size */ -+ job_dump, /* dump */ -+ job_get_type, /* get_type */ -+ add_queue, /* add_queue */ -+ remove_queue, /* remove_queue */ -+ job_signaled, /* signaled */ -+ no_satisfied, /* satisfied */ -+ no_signal, /* signal */ -+ no_get_fd, /* get_fd */ -+ job_map_access, /* map_access */ -+ default_get_sd, /* get_sd */ -+ default_set_sd, /* set_sd */ -+ no_lookup_name, /* lookup_name */ -+ no_open_file, /* open_file */ -+ no_close_handle, /* close_handle */ -+ job_destroy /* destroy */ -+}; -+ -+static struct job *create_job_object( struct directory *root, const struct unicode_str *name, -+ unsigned int attr, const struct security_descriptor *sd ) -+{ -+ struct job *job; -+ -+ if ((job = create_named_object_dir( root, name, attr, &job_ops ))) -+ { -+ if (get_error() != STATUS_OBJECT_NAME_EXISTS) -+ { -+ /* initialize it if it didn't already exist */ -+ if (sd) default_set_sd( &job->obj, sd, OWNER_SECURITY_INFORMATION | -+ GROUP_SECURITY_INFORMATION | -+ DACL_SECURITY_INFORMATION | -+ SACL_SECURITY_INFORMATION ); -+ list_init( &job->process_list ); -+ job->num_processes = 0; -+ job->limit_flags = 0; -+ } -+ } -+ return job; -+} -+ -+static struct job *get_job_obj( struct process *process, obj_handle_t handle, unsigned int access ) -+{ -+ return (struct job *)get_handle_obj( process, handle, access, &job_ops ); -+} -+ -+static struct object_type *job_get_type( struct object *obj ) -+{ -+ static const WCHAR name[] = {'J','o','b'}; -+ static const struct unicode_str str = { name, sizeof(name) }; -+ return get_object_type( &str ); -+}; -+ -+static unsigned int job_map_access( struct object *obj, unsigned int access ) -+{ -+ if (access & GENERIC_READ) access |= STANDARD_RIGHTS_READ; -+ if (access & GENERIC_WRITE) access |= STANDARD_RIGHTS_WRITE; -+ if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE; -+ if (access & GENERIC_ALL) access |= JOB_OBJECT_ALL_ACCESS; -+ return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); -+} -+ -+static int add_job_process( struct job *job, struct process *process ) -+{ -+ assert( job->obj.ops == &job_ops ); -+ -+ if (!process->running_threads) -+ { -+ set_error( STATUS_PROCESS_IS_TERMINATING ); -+ return 0; -+ } -+ if (process->job) -+ { -+ set_error( STATUS_ACCESS_DENIED ); -+ return 0; -+ } -+ -+ process->job = (struct job *)grab_object( job ); -+ list_add_tail( &job->process_list, &process->job_entry ); -+ job->num_processes++; -+ -+ return 1; -+} -+ -+/* called when a process has terminated, allow one additional process */ -+static void release_job_process( struct process *process ) -+{ -+ struct job *job = process->job; -+ -+ if (!job) -+ return; -+ -+ assert( job->obj.ops == &job_ops ); -+ assert( job->num_processes ); -+ job->num_processes--; -+} -+ -+static void terminate_job( struct job *job, int exit_code ) -+{ -+ for (;;) /* restart from the beginning of the list every time */ -+ { -+ struct process *process; -+ -+ /* find the first process associcated with this job and still running */ -+ LIST_FOR_EACH_ENTRY( process, &job->process_list, struct process, job_entry ) -+ { -+ if (process->running_threads) break; -+ } -+ if (&process->job_entry == &job->process_list) break; /* no process found */ -+ assert( process->job == job ); -+ terminate_process( process, NULL, exit_code ); -+ } -+} -+ -+static void job_destroy( struct object *obj ) -+{ -+ struct job *job = (struct job *)obj; -+ assert( obj->ops == &job_ops ); -+ -+ assert( !job->num_processes ); -+ assert( list_empty(&job->process_list) ); -+} -+ -+static void job_dump( struct object *obj, int verbose ) -+{ -+ struct job *job = (struct job *)obj; -+ assert( obj->ops == &job_ops ); -+ fprintf( stderr, "Job processes=%d\n", list_count(&job->process_list) ); -+} -+ -+static int job_signaled( struct object *obj, struct wait_queue_entry *entry ) -+{ -+ return 0; -+} - - struct ptid_entry - { -@@ -327,6 +479,7 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit - process->debug_children = 0; - process->is_terminating = 0; - process->is_terminated = 0; -+ process->job = NULL; - process->console = NULL; - process->startup_state = STARTUP_IN_PROGRESS; - process->startup_info = NULL; -@@ -425,6 +578,12 @@ static void process_destroy( struct object *obj ) - - close_process_handles( process ); - set_process_startup_state( process, STARTUP_ABORTED ); -+ -+ if (process->job) -+ { -+ list_remove( &process->job_entry ); -+ release_object( process->job ); -+ } - if (process->console) release_object( process->console ); - if (process->parent) release_object( process->parent ); - if (process->msg_fd) release_object( process->msg_fd ); -@@ -709,6 +868,7 @@ static void process_killed( struct process *process ) - remove_process_locks( process ); - set_process_startup_state( process, STARTUP_ABORTED ); - finish_process_tracing( process ); -+ release_job_process( process ); - start_sigkill_timer( process ); - wake_up( &process->obj, 0 ); - } -@@ -954,6 +1114,14 @@ DECL_HANDLER(new_process) - return; - } - -+ if (parent->job && (req->create_flags & CREATE_BREAKAWAY_FROM_JOB) && -+ !(parent->job->limit_flags & (JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))) -+ { -+ set_error( STATUS_ACCESS_DENIED ); -+ close( socket_fd ); -+ return; -+ } -+ - if (!req->info_size) /* create an orphaned process */ - { - create_process( socket_fd, NULL, 0 ); -@@ -1024,6 +1192,12 @@ DECL_HANDLER(new_process) - && !(req->create_flags & DEBUG_ONLY_THIS_PROCESS); - process->startup_info = (struct startup_info *)grab_object( info ); - -+ if (parent->job && !((req->create_flags & CREATE_BREAKAWAY_FROM_JOB) || -+ (parent->job->limit_flags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))) -+ { -+ add_job_process( parent->job, process ); -+ } -+ - /* connect to the window station */ - connect_process_winstation( process, current ); - -@@ -1361,3 +1535,88 @@ DECL_HANDLER(make_process_system) - shutdown_timeout = add_timeout_user( master_socket_timeout, server_shutdown_timeout, NULL ); - } - } -+ -+/* create a new job object */ -+DECL_HANDLER(create_job) -+{ -+ struct job *job; -+ struct unicode_str name; -+ struct directory *root = NULL; -+ const struct object_attributes *objattr = get_req_data(); -+ const struct security_descriptor *sd; -+ -+ if (!objattr_is_valid( objattr, get_req_data_size() )) return; -+ -+ sd = objattr->sd_len ? (const struct security_descriptor *)(objattr + 1) : NULL; -+ objattr_get_name( objattr, &name ); -+ -+ if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 ))) return; -+ -+ if ((job = create_job_object( root, &name, req->attributes, sd ))) -+ { -+ if (get_error() == STATUS_OBJECT_NAME_EXISTS) -+ reply->handle = alloc_handle( current->process, job, req->access, req->attributes ); -+ else -+ reply->handle = alloc_handle_no_access_check( current->process, job, req->access, req->attributes ); -+ release_object( job ); -+ } -+ if (root) release_object( root ); -+} -+ -+/* assign a job object to a process */ -+DECL_HANDLER(job_assign) -+{ -+ struct process *process; -+ struct job *job = get_job_obj( current->process, req->job_handle, JOB_OBJECT_ASSIGN_PROCESS ); -+ -+ if (job) -+ { -+ if ((process = get_process_from_handle( req->process_handle, PROCESS_SET_QUOTA | PROCESS_TERMINATE ))) -+ { -+ add_job_process( job, process ); -+ release_object(process); -+ } -+ release_object(job); -+ } -+} -+ -+/* check if a process is associated with a job */ -+DECL_HANDLER(process_in_job) -+{ -+ struct process *process; -+ struct job *job = get_job_obj( current->process, req->job_handle, JOB_OBJECT_ASSIGN_PROCESS ); -+ -+ if (job) -+ { -+ if ((process = get_process_from_handle( req->process_handle, PROCESS_QUERY_INFORMATION ))) -+ { -+ set_error( (process->job == job) ? STATUS_PROCESS_IN_JOB : STATUS_PROCESS_NOT_IN_JOB ); -+ release_object( process ); -+ } -+ release_object(job); -+ } -+} -+ -+/* terminate all processes associated with the job */ -+DECL_HANDLER(terminate_job) -+{ -+ struct job *job = get_job_obj( current->process, req->handle, JOB_OBJECT_TERMINATE ); -+ -+ if (job) -+ { -+ terminate_job( job, req->status ); -+ release_object( job ); -+ } -+} -+ -+/* update limits of the job object */ -+DECL_HANDLER(job_set_limits) -+{ -+ struct job *job = get_job_obj( current->process, req->handle, JOB_OBJECT_SET_ATTRIBUTES ); -+ -+ if (job) -+ { -+ job->limit_flags = req->limit_flags; -+ release_object( job ); -+ } -+} -diff --git a/server/process.h b/server/process.h -index da6d3da..ae83b0e 100644 ---- a/server/process.h -+++ b/server/process.h -@@ -26,6 +26,7 @@ - struct atom_table; - struct handle_table; - struct startup_info; -+struct job; - - /* process startup state */ - enum startup_state { STARTUP_IN_PROGRESS, STARTUP_DONE, STARTUP_ABORTED }; -@@ -76,6 +77,8 @@ struct process - unsigned int debug_children:1;/* also debug all child processes */ - unsigned int is_terminating:1;/* is process terminating? */ - unsigned int is_terminated:1; /* is process terminated? */ -+ struct job *job; /* job object ascoicated with this process */ -+ struct list job_entry; /* list entry for job object */ - struct list locks; /* list of file locks owned by the process */ - struct list classes; /* window classes owned by the process */ - struct console_input*console; /* console input */ -diff --git a/server/protocol.def b/server/protocol.def -index a34dde9..655a9ac 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -682,6 +682,33 @@ struct rawinput_device - obj_handle_t thandle; /* thread handle (in the current process) */ - @END - -+@REQ(create_job) -+ unsigned int access; /* wanted access rights */ -+ unsigned int attributes; /* object attributes */ -+ VARARG(objattr,object_attributes); /* object attributes */ -+@REPLY -+ obj_handle_t handle; /* handle to the job */ -+@END -+ -+@REQ(terminate_job) -+ obj_handle_t handle; -+ int status; -+@END -+ -+@REQ(process_in_job) -+ obj_handle_t job_handle; -+ obj_handle_t process_handle; -+@END -+ -+@REQ(job_assign) -+ obj_handle_t job_handle; -+ obj_handle_t process_handle; -+@END -+ -+@REQ(job_set_limits) -+ obj_handle_t handle; -+ unsigned int limit_flags; -+@END - - /* Retrieve information about a newly started process */ - @REQ(get_new_process_info) --- -2.3.3 - diff --git a/patches/server-JobObjects/0001-server-Implement-remaining-wineserver-calls-for-job-.patch b/patches/server-JobObjects/0001-server-Implement-remaining-wineserver-calls-for-job-.patch new file mode 100644 index 00000000..410b54e7 --- /dev/null +++ b/patches/server-JobObjects/0001-server-Implement-remaining-wineserver-calls-for-job-.patch @@ -0,0 +1,334 @@ +From f116e9e73f00bd6c65ebd087a1f7b23ceb9064a9 Mon Sep 17 00:00:00 2001 +From: Andrew Cook +Date: Thu, 26 Feb 2015 12:25:23 +1100 +Subject: server: Implement remaining wineserver calls for job objects. + +--- + dlls/kernel32/tests/process.c | 6 +--- + dlls/ntdll/sync.c | 76 +++++++++++++++++++++++++++++++++++++++---- + include/winnt.h | 4 +++ + server/process.c | 59 +++++++++++++++++++++++++++++++++ + server/process.h | 1 + + server/protocol.def | 14 ++++++++ + 6 files changed, 149 insertions(+), 11 deletions(-) + +diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c +index 1add23d..8c9a6ef 100644 +--- a/dlls/kernel32/tests/process.c ++++ b/dlls/kernel32/tests/process.c +@@ -2269,13 +2269,11 @@ static void test_TerminateJobObject(void) + ok(ret, "TerminateJobObject error %u\n", GetLastError()); + + dwret = WaitForSingleObject(pi.hProcess, 1000); +- todo_wine + ok(dwret == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", dwret); + if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0); + + ret = GetExitCodeProcess(pi.hProcess, &dwret); + ok(ret, "GetExitCodeProcess error %u\n", GetLastError()); +- todo_wine + ok(dwret == 123 || broken(dwret == 0) /* randomly fails on Win 2000 / XP */, + "wrong exitcode %u\n", dwret); + +@@ -2401,6 +2399,7 @@ static void test_CompletionPort(void) + port_info.CompletionKey = job; + port_info.CompletionPort = port; + ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info)); ++ todo_wine + ok(ret, "SetInformationJobObject error %u\n", GetLastError()); + + create_process("wait", &pi); +@@ -2498,7 +2497,6 @@ static void test_jobInheritance(HANDLE job) + out = FALSE; + ret = pIsProcessInJob(pi.hProcess, job, &out); + ok(ret, "IsProcessInJob error %u\n", GetLastError()); +- todo_wine + ok(out, "IsProcessInJob returned out=%u\n", out); + + dwret = WaitForSingleObject(pi.hProcess, 1000); +@@ -2526,9 +2524,7 @@ static void test_BreakawayOk(HANDLE job) + snprintf(buffer, MAX_PATH, "\"%s\" tests/process.c %s", selfname, "exit"); + + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi); +- todo_wine + ok(!ret, "CreateProcessA expected failure\n"); +- todo_wine + expect_eq_d(ERROR_ACCESS_DENIED, GetLastError()); + + if (ret) +diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c +index ce1a635..e001e28 100644 +--- a/dlls/ntdll/sync.c ++++ b/dlls/ntdll/sync.c +@@ -56,6 +56,7 @@ + #include "wine/server.h" + #include "wine/debug.h" + #include "ntdll_misc.h" ++#include "winnt.h" + + WINE_DEFAULT_DEBUG_CHANNEL(ntdll); + +@@ -613,8 +614,19 @@ NTSTATUS WINAPI NtOpenJobObject( PHANDLE handle, ACCESS_MASK access, const OBJEC + */ + NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status ) + { +- FIXME( "stub: %p %x\n", handle, status ); +- return STATUS_SUCCESS; ++ NTSTATUS ret; ++ ++ TRACE( "(%p, %d)\n", handle, status ); ++ ++ SERVER_START_REQ( terminate_job ) ++ { ++ req->handle = wine_server_obj_handle( handle ); ++ req->status = status; ++ ret = wine_server_call( req ); ++ } ++ SERVER_END_REQ; ++ ++ return ret; + } + + /****************************************************************************** +@@ -624,8 +636,17 @@ NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status ) + NTSTATUS WINAPI NtQueryInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info, + ULONG len, PULONG ret_len ) + { +- FIXME( "stub: %p %u %p %u %p\n", handle, class, info, len, ret_len ); +- return STATUS_NOT_IMPLEMENTED; ++ TRACE( "%p %u %p %u %p\n", handle, class, info, len, ret_len ); ++ ++ if (class >= MaxJobObjectInfoClass) ++ return STATUS_INVALID_PARAMETER; ++ ++ switch (class) ++ { ++ default: ++ FIXME( "stub: %p %u %p %u %p\n", handle, class, info, len, ret_len ); ++ return STATUS_NOT_IMPLEMENTED; ++ } + } + + /****************************************************************************** +@@ -634,8 +655,51 @@ NTSTATUS WINAPI NtQueryInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS c + */ + NTSTATUS WINAPI NtSetInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info, ULONG len ) + { +- FIXME( "stub: %p %u %p %u\n", handle, class, info, len ); +- return STATUS_SUCCESS; ++ JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit; ++ NTSTATUS status = STATUS_SUCCESS; ++ ++ TRACE( "(%p, %u, %p, %u)\n", handle, class, info, len ); ++ ++ if (class >= MaxJobObjectInfoClass) ++ return STATUS_INVALID_PARAMETER; ++ ++ switch (class) ++ { ++ ++ case JobObjectExtendedLimitInformation: ++ if (len != sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)) ++ return STATUS_INVALID_PARAMETER; ++ ++ basic_limit = &(((JOBOBJECT_EXTENDED_LIMIT_INFORMATION *)info)->BasicLimitInformation); ++ if (basic_limit->LimitFlags & ~JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS) ++ return STATUS_INVALID_PARAMETER; ++ ++ goto set_basic_limits; ++ ++ case JobObjectBasicLimitInformation: ++ if (len != sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION)) ++ return STATUS_INVALID_PARAMETER; ++ ++ basic_limit = info; ++ if (basic_limit->LimitFlags & ~JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS) ++ return STATUS_INVALID_PARAMETER; ++ ++ set_basic_limits: ++ SERVER_START_REQ( set_job_limits ) ++ { ++ req->handle = wine_server_obj_handle( handle ); ++ req->limit_flags = basic_limit->LimitFlags; ++ status = wine_server_call( req ); ++ } ++ SERVER_END_REQ; ++ break; ++ ++ default: ++ FIXME( "stub: %p %u %p %u\n", handle, class, info, len ); ++ return STATUS_NOT_IMPLEMENTED; ++ } ++ ++ return status; + } + + /****************************************************************************** +diff --git a/include/winnt.h b/include/winnt.h +index 4b06b2c..c2aa50e 100644 +--- a/include/winnt.h ++++ b/include/winnt.h +@@ -5610,6 +5610,10 @@ typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION { + #define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 + #define JOB_OBJECT_LIMIT_SUBSET_AFFINITY 0x00004000 + ++#define JOB_OBJECT_LIMIT_VALID_FLAGS 0x0007ffff ++#define JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS 0x000000ff ++#define JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS 0x00007fff ++ + typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP + { + RelationProcessorCore = 0, +diff --git a/server/process.c b/server/process.c +index f9738c0..a1ab8c7 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -65,6 +65,7 @@ static unsigned int process_map_access( struct object *obj, unsigned int access + static struct security_descriptor *process_get_sd( struct object *obj ); + static void process_poll_event( struct fd *fd, int event ); + static void process_destroy( struct object *obj ); ++static void terminate_process( struct process *process, struct thread *skip, int exit_code ); + + static const struct object_ops process_ops = + { +@@ -147,6 +148,7 @@ struct job + struct object obj; /* object header */ + struct list process_list; /* list of all processes */ + int num_processes; /* count of running processes */ ++ int limit_flags; /* limit flags */ + }; + + static const struct object_ops job_ops = +@@ -185,6 +187,7 @@ static struct job *create_job_object( struct directory *root, const struct unico + SACL_SECURITY_INFORMATION ); + list_init( &job->process_list ); + job->num_processes = 0; ++ job->limit_flags = 0; + } + } + return job; +@@ -223,6 +226,7 @@ static void add_job_process( struct job *job, struct process *process ) + set_error( STATUS_ACCESS_DENIED ); + return; + } ++ + process->job = (struct job *)grab_object( job ); + list_add_tail( &job->process_list, &process->job_entry ); + job->num_processes++; +@@ -239,6 +243,23 @@ static void release_job_process( struct process *process ) + job->num_processes--; + } + ++static void terminate_job( struct job *job, int exit_code ) ++{ ++ for (;;) /* restart from the beginning of the list every time */ ++ { ++ struct process *process; ++ ++ /* find the first process associcated with this job and still running */ ++ LIST_FOR_EACH_ENTRY( process, &job->process_list, struct process, job_entry ) ++ { ++ if (process->running_threads) break; ++ } ++ if (&process->job_entry == &job->process_list) break; /* no process found */ ++ assert( process->job == job ); ++ terminate_process( process, NULL, exit_code ); ++ } ++} ++ + static void job_destroy( struct object *obj ) + { + struct job *job = (struct job *)obj; +@@ -1087,6 +1108,14 @@ DECL_HANDLER(new_process) + return; + } + ++ if (parent->job && (req->create_flags & CREATE_BREAKAWAY_FROM_JOB) && ++ !(parent->job->limit_flags & (JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))) ++ { ++ set_error( STATUS_ACCESS_DENIED ); ++ close( socket_fd ); ++ return; ++ } ++ + if (!req->info_size) /* create an orphaned process */ + { + create_process( socket_fd, NULL, 0 ); +@@ -1157,6 +1186,12 @@ DECL_HANDLER(new_process) + && !(req->create_flags & DEBUG_ONLY_THIS_PROCESS); + process->startup_info = (struct startup_info *)grab_object( info ); + ++ if (parent->job && !((req->create_flags & CREATE_BREAKAWAY_FROM_JOB) || ++ (parent->job->limit_flags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))) ++ { ++ add_job_process( parent->job, process ); ++ } ++ + /* connect to the window station */ + connect_process_winstation( process, current ); + +@@ -1559,3 +1594,27 @@ DECL_HANDLER(process_in_job) + } + release_object( process ); + } ++ ++/* terminate all processes associated with the job */ ++DECL_HANDLER(terminate_job) ++{ ++ struct job *job = get_job_obj( current->process, req->handle, JOB_OBJECT_TERMINATE ); ++ ++ if (job) ++ { ++ terminate_job( job, req->status ); ++ release_object( job ); ++ } ++} ++ ++/* update limits of the job object */ ++DECL_HANDLER(set_job_limits) ++{ ++ struct job *job = get_job_obj( current->process, req->handle, JOB_OBJECT_SET_ATTRIBUTES ); ++ ++ if (job) ++ { ++ job->limit_flags = req->limit_flags; ++ release_object( job ); ++ } ++} +diff --git a/server/process.h b/server/process.h +index 0cf9514..ae83b0e 100644 +--- a/server/process.h ++++ b/server/process.h +@@ -26,6 +26,7 @@ + struct atom_table; + struct handle_table; + struct startup_info; ++struct job; + + /* process startup state */ + enum startup_state { STARTUP_IN_PROGRESS, STARTUP_DONE, STARTUP_ABORTED }; +diff --git a/server/protocol.def b/server/protocol.def +index b85adca..0077aa4 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3528,3 +3528,17 @@ enum coords_relative + obj_handle_t job; /* handle to the job */ + obj_handle_t process; /* handle to the process */ + @END ++ ++ ++/* Terminate all processes associated with the job */ ++@REQ(terminate_job) ++ obj_handle_t handle; /* handle to the job */ ++ int status; /* exitcode of the process */ ++@END ++ ++ ++/* Update limits of the job object */ ++@REQ(set_job_limits) ++ obj_handle_t handle; /* handle to the job */ ++ unsigned int limit_flags; /* limit flags */ ++@END +-- +2.3.3 + diff --git a/patches/server-JobObjects/0002-server-Implement-completion-messages-for-job-objects.patch b/patches/server-JobObjects/0002-server-Implement-completion-messages-for-job-objects.patch index f1e2c8a4..b409a6d7 100644 --- a/patches/server-JobObjects/0002-server-Implement-completion-messages-for-job-objects.patch +++ b/patches/server-JobObjects/0002-server-Implement-completion-messages-for-job-objects.patch @@ -1,4 +1,4 @@ -From 2dc3e01bbb999ff93918375bdc5071eb9439a011 Mon Sep 17 00:00:00 2001 +From 3babb8a2681bd530008b0d268cde0b5788177097 Mon Sep 17 00:00:00 2001 From: Andrew Cook Date: Thu, 26 Feb 2015 13:02:36 +1100 Subject: server: Implement completion messages for job objects. @@ -10,15 +10,15 @@ coding style by Sebastian Lackner . --- dlls/kernel32/tests/process.c | 4 ---- dlls/ntdll/sync.c | 15 +++++++++++++++ - server/process.c | 44 +++++++++++++++++++++++++++++++++++++++++++ - server/protocol.def | 6 ++++++ - 4 files changed, 65 insertions(+), 4 deletions(-) + server/process.c | 45 +++++++++++++++++++++++++++++++++++++++++++ + server/protocol.def | 8 ++++++++ + 4 files changed, 68 insertions(+), 4 deletions(-) diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c -index 6c2f86d..911fad7 100644 +index 8c9a6ef..a86e331 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c -@@ -2375,7 +2375,6 @@ static void test_CompletionPort(void) +@@ -2399,7 +2399,6 @@ static void test_CompletionPort(void) port_info.CompletionKey = job; port_info.CompletionPort = port; ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info)); @@ -26,7 +26,7 @@ index 6c2f86d..911fad7 100644 ok(ret, "SetInformationJobObject error %u\n", GetLastError()); create_process("wait", &pi); -@@ -2383,16 +2382,13 @@ static void test_CompletionPort(void) +@@ -2407,16 +2406,13 @@ static void test_CompletionPort(void) ret = pAssignProcessToJobObject(job, pi.hProcess); ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); @@ -44,7 +44,7 @@ index 6c2f86d..911fad7 100644 CloseHandle(pi.hProcess); diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c -index a0b8c15..c754df6 100644 +index e001e28..87ff3e0 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -694,6 +694,21 @@ NTSTATUS WINAPI NtSetInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS cla @@ -55,12 +55,12 @@ index a0b8c15..c754df6 100644 + if (len != sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT)) + return STATUS_INVALID_PARAMETER; + -+ SERVER_START_REQ( job_set_completion ) ++ SERVER_START_REQ( set_job_completion ) + { + JOBOBJECT_ASSOCIATE_COMPLETION_PORT *port_info = info; + req->handle = wine_server_obj_handle( handle ); -+ req->port = wine_server_obj_handle( port_info->CompletionPort ); -+ req->key = wine_server_client_ptr( port_info->CompletionKey ); ++ req->port = wine_server_obj_handle( port_info->CompletionPort ); ++ req->key = wine_server_client_ptr( port_info->CompletionKey ); + status = wine_server_call(req); + } + SERVER_END_REQ; @@ -70,7 +70,7 @@ index a0b8c15..c754df6 100644 FIXME( "stub: %p %u %p %u\n", handle, class, info, len ); return STATUS_NOT_IMPLEMENTED; diff --git a/server/process.c b/server/process.c -index 6384203..e02b7af 100644 +index a1ab8c7..10193ef 100644 --- a/server/process.c +++ b/server/process.c @@ -149,6 +149,9 @@ struct job @@ -103,19 +103,20 @@ index 6384203..e02b7af 100644 + add_completion(job->completion_port, job->completion_key, pid, STATUS_SUCCESS, msg); +} + - static int add_job_process( struct job *job, struct process *process ) + static void add_job_process( struct job *job, struct process *process ) { - assert( job->obj.ops == &job_ops ); -@@ -233,6 +245,7 @@ static int add_job_process( struct job *job, struct process *process ) + if (!process->running_threads) +@@ -230,6 +242,8 @@ static void add_job_process( struct job *job, struct process *process ) + process->job = (struct job *)grab_object( job ); list_add_tail( &job->process_list, &process->job_entry ); job->num_processes++; - ++ + add_job_completion( job, JOB_OBJECT_MSG_NEW_PROCESS, get_process_id(process) ); - return 1; } -@@ -247,10 +260,20 @@ static void release_job_process( struct process *process ) - assert( job->obj.ops == &job_ops ); + /* called when a process has terminated, allow one additional process */ +@@ -241,10 +255,20 @@ static void release_job_process( struct process *process ) + assert( job->num_processes ); job->num_processes--; + @@ -135,7 +136,7 @@ index 6384203..e02b7af 100644 for (;;) /* restart from the beginning of the list every time */ { struct process *process; -@@ -264,6 +287,8 @@ static void terminate_job( struct job *job, int exit_code ) +@@ -258,6 +282,8 @@ static void terminate_job( struct job *job, int exit_code ) assert( process->job == job ); terminate_process( process, NULL, exit_code ); } @@ -144,7 +145,7 @@ index 6384203..e02b7af 100644 } static void job_destroy( struct object *obj ) -@@ -273,6 +298,9 @@ static void job_destroy( struct object *obj ) +@@ -267,6 +293,9 @@ static void job_destroy( struct object *obj ) assert( !job->num_processes ); assert( list_empty(&job->process_list) ); @@ -154,12 +155,12 @@ index 6384203..e02b7af 100644 } static void job_dump( struct object *obj, int verbose ) -@@ -1620,3 +1648,19 @@ DECL_HANDLER(job_set_limits) +@@ -1618,3 +1647,19 @@ DECL_HANDLER(set_job_limits) release_object( job ); } } + -+DECL_HANDLER(job_set_completion) ++DECL_HANDLER(set_job_completion) +{ + struct job *job = get_job_obj( current->process, req->handle, JOB_OBJECT_SET_ATTRIBUTES ); + @@ -175,22 +176,21 @@ index 6384203..e02b7af 100644 + } +} diff --git a/server/protocol.def b/server/protocol.def -index 655a9ac..deaaa7b 100644 +index 0077aa4..c88c970 100644 --- a/server/protocol.def +++ b/server/protocol.def -@@ -710,6 +710,12 @@ struct rawinput_device - unsigned int limit_flags; +@@ -3542,3 +3542,11 @@ enum coords_relative + obj_handle_t handle; /* handle to the job */ + unsigned int limit_flags; /* limit flags */ @END - -+@REQ(job_set_completion) -+ obj_handle_t handle; -+ obj_handle_t port; -+ client_ptr_t key; -+@END + - /* Retrieve information about a newly started process */ - @REQ(get_new_process_info) - obj_handle_t info; /* info handle returned from new_process_request */ ++ ++/* Set a job completion port/key */ ++@REQ(set_job_completion) ++ obj_handle_t handle; /* handle to the job */ ++ obj_handle_t port; /* completion port */ ++ client_ptr_t key; /* completion key */ ++@END -- 2.3.3 diff --git a/patches/server-JobObjects/0003-server-Properly-track-handle-count-of-objects.patch b/patches/server-JobObjects/0003-server-Properly-track-handle-count-of-objects.patch index 8985855d..72201bf2 100644 --- a/patches/server-JobObjects/0003-server-Properly-track-handle-count-of-objects.patch +++ b/patches/server-JobObjects/0003-server-Properly-track-handle-count-of-objects.patch @@ -1,4 +1,4 @@ -From 126ffd832a29072552150c335b4f3c945bce5bbe Mon Sep 17 00:00:00 2001 +From 7d8fc002a6adf69f64f635d37b19ddc892283f03 Mon Sep 17 00:00:00 2001 From: Andrew Cook Date: Thu, 26 Feb 2015 10:51:16 +1100 Subject: server: Properly track handle count of objects. @@ -12,10 +12,10 @@ Subject: server: Properly track handle count of objects. 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c -index 47a2614..05f18c0 100644 +index f5f75c6..b337444 100644 --- a/dlls/ntdll/om.c +++ b/dlls/ntdll/om.c -@@ -78,7 +78,7 @@ NTSTATUS WINAPI NtQueryObject(IN HANDLE handle, +@@ -77,7 +77,7 @@ NTSTATUS WINAPI NtQueryObject(IN HANDLE handle, memset( p, 0, sizeof(*p) ); p->GrantedAccess = reply->access; p->PointerCount = reply->ref_count; @@ -128,10 +128,10 @@ index 3817c75..978baeb 100644 struct list wait_queue; struct object_name *name; diff --git a/server/protocol.def b/server/protocol.def -index 126c2a7..2c5af48 100644 +index c88c970..fdebf29 100644 --- a/server/protocol.def +++ b/server/protocol.def -@@ -3292,6 +3292,7 @@ enum coords_relative +@@ -3269,6 +3269,7 @@ enum coords_relative @REPLY unsigned int access; /* granted access mask */ unsigned int ref_count; /* object ref count */ @@ -140,5 +140,5 @@ index 126c2a7..2c5af48 100644 VARARG(name,unicode_str); /* object name */ @END -- -2.3.0 +2.3.3 diff --git a/patches/server-JobObjects/0004-server-Implement-JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE.patch b/patches/server-JobObjects/0004-server-Implement-JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE.patch index e31d2f6f..4ea24483 100644 --- a/patches/server-JobObjects/0004-server-Implement-JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE.patch +++ b/patches/server-JobObjects/0004-server-Implement-JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE.patch @@ -1,4 +1,4 @@ -From dedf23f9a61a8ef5bcc23a229646d1244e859546 Mon Sep 17 00:00:00 2001 +From e70c80c4f78ac6306629d79f86d8c1c5439aaa17 Mon Sep 17 00:00:00 2001 From: Andrew Cook Date: Thu, 26 Feb 2015 13:10:41 +1100 Subject: server: Implement JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE. @@ -9,10 +9,10 @@ Subject: server: Implement JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE. 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c -index 911fad7..66e0863 100644 +index a86e331..4f51cea 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c -@@ -2425,7 +2425,6 @@ static void test_KillOnJobClose(void) +@@ -2449,7 +2449,6 @@ static void test_KillOnJobClose(void) CloseHandle(job); dwret = WaitForSingleObject(pi.hProcess, 1000); @@ -21,7 +21,7 @@ index 911fad7..66e0863 100644 if (dwret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0); diff --git a/server/process.c b/server/process.c -index e02b7af..f36548e 100644 +index 10193ef..89c029e 100644 --- a/server/process.c +++ b/server/process.c @@ -141,6 +141,7 @@ static void job_dump( struct object *obj, int verbose ); @@ -41,7 +41,7 @@ index e02b7af..f36548e 100644 job_destroy /* destroy */ }; -@@ -291,6 +292,20 @@ static void terminate_job( struct job *job, int exit_code ) +@@ -286,6 +287,20 @@ static void terminate_job( struct job *job, int exit_code ) job->terminating = 0; } diff --git a/patches/server-JobObjects/0006-kernel32-tests-Add-tests-for-waiting-on-an-job-objec.patch b/patches/server-JobObjects/0005-kernel32-tests-Add-tests-for-waiting-on-an-job-objec.patch similarity index 94% rename from patches/server-JobObjects/0006-kernel32-tests-Add-tests-for-waiting-on-an-job-objec.patch rename to patches/server-JobObjects/0005-kernel32-tests-Add-tests-for-waiting-on-an-job-objec.patch index 0dea1bc6..f90ece4a 100644 --- a/patches/server-JobObjects/0006-kernel32-tests-Add-tests-for-waiting-on-an-job-objec.patch +++ b/patches/server-JobObjects/0005-kernel32-tests-Add-tests-for-waiting-on-an-job-objec.patch @@ -1,4 +1,4 @@ -From f55bd1380e177f8fd48003fc3b1efae0c16b4c42 Mon Sep 17 00:00:00 2001 +From c86188e18efaf5ece7b4d85ccee4089208e392fa Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sat, 28 Feb 2015 06:09:16 +0100 Subject: kernel32/tests: Add tests for waiting on an job object. @@ -8,10 +8,10 @@ Subject: kernel32/tests: Add tests for waiting on an job object. 1 file changed, 85 insertions(+) diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c -index e20fb92..31a4c1d 100644 +index 4f51cea..aaa1a6e 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c -@@ -2442,6 +2442,90 @@ static void test_KillOnJobClose(void) +@@ -2456,6 +2456,90 @@ static void test_KillOnJobClose(void) CloseHandle(pi.hThread); } @@ -102,7 +102,7 @@ index e20fb92..31a4c1d 100644 static HANDLE test_AddSelfToJob(void) { HANDLE job; -@@ -2662,6 +2746,7 @@ START_TEST(process) +@@ -2676,6 +2760,7 @@ START_TEST(process) test_QueryInformationJobObject(); test_CompletionPort(); test_KillOnJobClose(); diff --git a/patches/server-JobObjects/0005-server-Support-NULL-job-handles-in-IsProcessInJob.patch b/patches/server-JobObjects/0005-server-Support-NULL-job-handles-in-IsProcessInJob.patch deleted file mode 100644 index afc34021..00000000 --- a/patches/server-JobObjects/0005-server-Support-NULL-job-handles-in-IsProcessInJob.patch +++ /dev/null @@ -1,71 +0,0 @@ -From b55b5ab63248360985a6ff01e1d2c98867e05a16 Mon Sep 17 00:00:00 2001 -From: Andrew Cook -Date: Sat, 28 Feb 2015 13:37:47 +1100 -Subject: server: Support NULL job handles in IsProcessInJob. - ---- - dlls/kernel32/tests/process.c | 10 ++++++++++ - server/process.c | 14 +++++++++----- - 2 files changed, 19 insertions(+), 5 deletions(-) - -diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c -index 66e0863..e20fb92 100644 ---- a/dlls/kernel32/tests/process.c -+++ b/dlls/kernel32/tests/process.c -@@ -2203,6 +2203,11 @@ static void test_IsProcessInJob(void) - ok(ret, "IsProcessInJob error %u\n", GetLastError()); - ok(!out, "IsProcessInJob returned out=%u\n", out); - -+ out = TRUE; -+ ret = pIsProcessInJob(pi.hProcess, NULL, &out); -+ ok(ret, "IsProcessInJob error %u\n", GetLastError()); -+ ok(!out, "IsProcessInJob returned out=%u\n", out); -+ - ret = pAssignProcessToJobObject(job, pi.hProcess); - ok(ret, "AssignProcessToJobObject error %u\n", GetLastError()); - -@@ -2211,6 +2216,11 @@ static void test_IsProcessInJob(void) - ok(ret, "IsProcessInJob error %u\n", GetLastError()); - ok(out, "IsProcessInJob returned out=%u\n", out); - -+ out = FALSE; -+ ret = pIsProcessInJob(pi.hProcess, NULL, &out); -+ ok(ret, "IsProcessInJob error %u\n", GetLastError()); -+ ok(out, "IsProcessInJob returned out=%u\n", out); -+ - TerminateProcess(pi.hProcess, 0); - - dwret = WaitForSingleObject(pi.hProcess, 1000); -diff --git a/server/process.c b/server/process.c -index f36548e..db5a3b5 100644 ---- a/server/process.c -+++ b/server/process.c -@@ -1627,16 +1627,20 @@ DECL_HANDLER(job_assign) - DECL_HANDLER(process_in_job) - { - struct process *process; -- struct job *job = get_job_obj( current->process, req->job_handle, JOB_OBJECT_ASSIGN_PROCESS ); -+ struct job *job; - -- if (job) -+ if ((process = get_process_from_handle( req->process_handle, PROCESS_QUERY_INFORMATION ))) - { -- if ((process = get_process_from_handle( req->process_handle, PROCESS_QUERY_INFORMATION ))) -+ if (!req->job_handle) -+ { -+ set_error( (process->job) ? STATUS_PROCESS_IN_JOB : STATUS_PROCESS_NOT_IN_JOB ); -+ } -+ else if ((job = get_job_obj( current->process, req->job_handle, JOB_OBJECT_QUERY ))) - { - set_error( (process->job == job) ? STATUS_PROCESS_IN_JOB : STATUS_PROCESS_NOT_IN_JOB ); -- release_object( process ); -+ release_object( job ); - } -- release_object(job); -+ release_object( process ); - } - } - --- -2.3.3 - diff --git a/patches/server-JobObjects/0007-server-Implement-waiting-for-job-objects.patch b/patches/server-JobObjects/0006-server-Implement-waiting-for-job-objects.patch similarity index 84% rename from patches/server-JobObjects/0007-server-Implement-waiting-for-job-objects.patch rename to patches/server-JobObjects/0006-server-Implement-waiting-for-job-objects.patch index c13e4914..3de51274 100644 --- a/patches/server-JobObjects/0007-server-Implement-waiting-for-job-objects.patch +++ b/patches/server-JobObjects/0006-server-Implement-waiting-for-job-objects.patch @@ -1,4 +1,4 @@ -From 0bd977f5878df0fbe053847aecf9ae0ed7cd110d Mon Sep 17 00:00:00 2001 +From 2885683ee26ca39acc9158c804b5287da43585ac Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sat, 28 Feb 2015 06:58:48 +0100 Subject: server: Implement waiting for job objects. @@ -9,10 +9,10 @@ Subject: server: Implement waiting for job objects. 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c -index e0da270..cf2c1df 100644 +index aaa1a6e..c325d32 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c -@@ -2501,7 +2501,6 @@ static void test_WaitForJobObject(void) +@@ -2482,7 +2482,6 @@ static void test_WaitForJobObject(void) ok(ret, "TerminateJobObject error %u\n", GetLastError()); dwret = WaitForSingleObject(job, 500); @@ -20,7 +20,7 @@ index e0da270..cf2c1df 100644 ok(dwret == WAIT_OBJECT_0 || broken(dwret == WAIT_TIMEOUT), "WaitForSingleObject returned %u\n", dwret); -@@ -2510,7 +2509,6 @@ static void test_WaitForJobObject(void) +@@ -2491,7 +2490,6 @@ static void test_WaitForJobObject(void) CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(job); @@ -29,7 +29,7 @@ index e0da270..cf2c1df 100644 return; } diff --git a/server/process.c b/server/process.c -index db5a3b5..673ce20 100644 +index 89c029e..8c654b4 100644 --- a/server/process.c +++ b/server/process.c @@ -151,6 +151,7 @@ struct job @@ -48,7 +48,7 @@ index db5a3b5..673ce20 100644 job->completion_port = NULL; job->completion_key = 0; } -@@ -290,6 +292,8 @@ static void terminate_job( struct job *job, int exit_code ) +@@ -285,6 +287,8 @@ static void terminate_job( struct job *job, int exit_code ) } job->terminating = 0; @@ -57,7 +57,7 @@ index db5a3b5..673ce20 100644 } static int job_close_handle( struct object *obj, struct process *process, obj_handle_t handle ) -@@ -327,7 +331,8 @@ static void job_dump( struct object *obj, int verbose ) +@@ -322,7 +326,8 @@ static void job_dump( struct object *obj, int verbose ) static int job_signaled( struct object *obj, struct wait_queue_entry *entry ) { @@ -68,5 +68,5 @@ index db5a3b5..673ce20 100644 struct ptid_entry -- -2.3.0 +2.3.3 diff --git a/patches/server-JobObjects/0008-ntdll-Implement-NtQueryInformationJobObject-stub-fun.patch b/patches/server-JobObjects/0007-ntdll-Implement-NtQueryInformationJobObject-stub-fun.patch similarity index 91% rename from patches/server-JobObjects/0008-ntdll-Implement-NtQueryInformationJobObject-stub-fun.patch rename to patches/server-JobObjects/0007-ntdll-Implement-NtQueryInformationJobObject-stub-fun.patch index c4f10d58..e2b2e116 100644 --- a/patches/server-JobObjects/0008-ntdll-Implement-NtQueryInformationJobObject-stub-fun.patch +++ b/patches/server-JobObjects/0007-ntdll-Implement-NtQueryInformationJobObject-stub-fun.patch @@ -1,4 +1,4 @@ -From 5aaa9bb4d39cfd92b4c913aa961854657dbf944d Mon Sep 17 00:00:00 2001 +From 55894316559d36c433e8aa8ae6e6957fa651d09a Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Thu, 12 Mar 2015 22:19:50 +0100 Subject: ntdll: Implement NtQueryInformationJobObject stub function. @@ -8,10 +8,10 @@ Subject: ntdll: Implement NtQueryInformationJobObject stub function. 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c -index ef4a4cb..6f09b83 100644 +index 87ff3e0..9a7a6d0 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c -@@ -638,15 +638,37 @@ NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status ) +@@ -636,15 +636,37 @@ NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status ) NTSTATUS WINAPI NtQueryInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info, ULONG len, PULONG ret_len ) { @@ -51,5 +51,5 @@ index ef4a4cb..6f09b83 100644 } } -- -2.3.1 +2.3.3 diff --git a/patches/server-OpenProcess/0001-server-Return-error-when-opening-a-terminating-proce.patch b/patches/server-OpenProcess/0001-server-Return-error-when-opening-a-terminating-proce.patch index e16c331b..eb42ce84 100644 --- a/patches/server-OpenProcess/0001-server-Return-error-when-opening-a-terminating-proce.patch +++ b/patches/server-OpenProcess/0001-server-Return-error-when-opening-a-terminating-proce.patch @@ -1,18 +1,18 @@ -From c45e6864494332d04e7e93be02a0ee8222bd9383 Mon Sep 17 00:00:00 2001 +From bc7cb674c2b15f6dc603b9271a684d6aefe3a7d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Thu, 14 Aug 2014 03:05:52 +0200 Subject: server: Return error when opening a terminating process. (try 3) --- - server/process.c | 7 ++++++- - server/process.h | 1 + + server/process.c | 7 ++++++- + server/process.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/server/process.c b/server/process.c -index 426bcca..0574a32 100644 +index 5be3b00..f9738c0 100644 --- a/server/process.c +++ b/server/process.c -@@ -268,6 +268,7 @@ void shutdown_master_socket(void) +@@ -394,6 +394,7 @@ void shutdown_master_socket(void) /* final cleanup once we are sure a process is really dead */ static void process_died( struct process *process ) { @@ -20,15 +20,15 @@ index 426bcca..0574a32 100644 if (debug_level) fprintf( stderr, "%04x: *process killed*\n", process->id ); if (!process->is_system) { -@@ -324,6 +325,7 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit +@@ -450,6 +451,7 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit process->is_system = 0; process->debug_children = 0; process->is_terminating = 0; + process->is_terminated = 0; + process->job = NULL; process->console = NULL; process->startup_state = STARTUP_IN_PROGRESS; - process->startup_info = NULL; -@@ -1129,7 +1131,10 @@ DECL_HANDLER(open_process) +@@ -1278,7 +1280,10 @@ DECL_HANDLER(open_process) reply->handle = 0; if (process) { @@ -41,7 +41,7 @@ index 426bcca..0574a32 100644 } } diff --git a/server/process.h b/server/process.h -index a50b537..da6d3da 100644 +index 58c313a..0cf9514 100644 --- a/server/process.h +++ b/server/process.h @@ -75,6 +75,7 @@ struct process @@ -49,9 +49,9 @@ index a50b537..da6d3da 100644 unsigned int debug_children:1;/* also debug all child processes */ unsigned int is_terminating:1;/* is process terminating? */ + unsigned int is_terminated:1; /* is process terminated? */ + struct job *job; /* job object ascoicated with this process */ + struct list job_entry; /* list entry for job object */ struct list locks; /* list of file locks owned by the process */ - struct list classes; /* window classes owned by the process */ - struct console_input*console; /* console input */ -- -1.7.9.5 +2.3.3 diff --git a/patches/server-Stored_ACLs/0005-server-Retrieve-file-security-attributes-with-extend.patch b/patches/server-Stored_ACLs/0005-server-Retrieve-file-security-attributes-with-extend.patch index 2b8fbf6a..bf82ec12 100644 --- a/patches/server-Stored_ACLs/0005-server-Retrieve-file-security-attributes-with-extend.patch +++ b/patches/server-Stored_ACLs/0005-server-Retrieve-file-security-attributes-with-extend.patch @@ -1,56 +1,93 @@ -From bea49452dfb1e768b03fc75fced9b733d1edd73f Mon Sep 17 00:00:00 2001 +From 148550ffa4aeae7903d6654373011ad282ce59dc Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Fri, 18 Apr 2014 14:01:35 -0600 Subject: server: Retrieve file security attributes with extended file attributes. (try 7) --- - dlls/advapi32/tests/security.c | 49 ++++++++++++++++++++-------------------- - server/file.c | 26 ++++++++++++++++++--- - 2 files changed, 47 insertions(+), 28 deletions(-) + dlls/advapi32/tests/security.c | 57 +++++++++++++++++++++++++----------------- + server/file.c | 26 ++++++++++++++++--- + 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c -index b44496a..02094a4 100644 +index a757c22..3f97a82 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c -@@ -3192,24 +3192,24 @@ static void test_CreateDirectoryA(void) - bret = pGetAce(pDacl, 0, (VOID **)&ace); - ok(bret, "Failed to get Current User ACE.\n"); - bret = EqualSid(&ace->SidStart, user_sid); -- todo_wine ok(bret, "Current User ACE != Current User SID.\n"); -- todo_wine ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE), -- "Current User ACE has unexpected flags (0x%x != 0x03)\n", -- ((ACE_HEADER *)ace)->AceFlags); -- ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n", -- ace->Mask); -+ ok(bret, "Current User ACE != Current User SID.\n"); -+ ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE), -+ "Current User ACE has unexpected flags (0x%x != 0x03)\n", -+ ((ACE_HEADER *)ace)->AceFlags); -+ todo_wine ok(ace->Mask == 0x1f01ff, -+ "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n", ace->Mask); +@@ -3109,7 +3109,7 @@ static void get_nt_pathW(const char *name, UNICODE_STRING *nameW) + } + + static void test_inherited_dacl(PACL dacl, PSID admin_sid, PSID user_sid, DWORD flags, DWORD mask, +- BOOL todo_count, BOOL todo_sid, BOOL todo_flags, int line) ++ BOOL todo_count, BOOL todo_sid, BOOL todo_flags, BOOL todo_mask, int line) + { + ACL_SIZE_INFORMATION acl_size; + ACCESS_ALLOWED_ACE *ace; +@@ -3150,9 +3150,15 @@ static void test_inherited_dacl(PACL dacl, PSID admin_sid, PSID user_sid, DWORD + "Current User ACE has unexpected flags (0x%x != 0x%x)\n", + ((ACE_HEADER *)ace)->AceFlags, flags); + +- ok_(__FILE__, line)(ace->Mask == mask, +- "Current User ACE has unexpected mask (0x%x != 0x%x)\n", +- ace->Mask, mask); ++ if (todo_mask) ++ todo_wine ++ ok_(__FILE__, line)(ace->Mask == mask, ++ "Current User ACE has unexpected mask (0x%x != 0x%x)\n", ++ ace->Mask, mask); ++ else ++ ok_(__FILE__, line)(ace->Mask == mask, ++ "Current User ACE has unexpected mask (0x%x != 0x%x)\n", ++ ace->Mask, mask); } if (acl_size.AceCount > 1) { - bret = pGetAce(pDacl, 1, (VOID **)&ace); - ok(bret, "Failed to get Administators Group ACE.\n"); - bret = EqualSid(&ace->SidStart, admin_sid); -- todo_wine ok(bret, "Administators Group ACE != Administators Group SID.\n"); -- todo_wine ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE), -- "Administators Group ACE has unexpected flags (0x%x != 0x03)\n", -- ((ACE_HEADER *)ace)->AceFlags); -- ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n", -- ace->Mask); -+ ok(bret, "Administators Group ACE != Administators Group SID.\n"); -+ ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE), -+ "Administators Group ACE has unexpected flags (0x%x != 0x03)\n", -+ ((ACE_HEADER *)ace)->AceFlags); -+ todo_wine ok(ace->Mask == 0x1f01ff, -+ "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n", ace->Mask); +@@ -3176,9 +3182,15 @@ static void test_inherited_dacl(PACL dacl, PSID admin_sid, PSID user_sid, DWORD + "Administators Group ACE has unexpected flags (0x%x != 0x%x)\n", + ((ACE_HEADER *)ace)->AceFlags, flags); + +- ok_(__FILE__, line)(ace->Mask == mask, +- "Administators Group ACE has unexpected mask (0x%x != 0x%x)\n", +- ace->Mask, mask); ++ if (todo_mask) ++ todo_wine ++ ok_(__FILE__, line)(ace->Mask == mask, ++ "Administators Group ACE has unexpected mask (0x%x != 0x%x)\n", ++ ace->Mask, mask); ++ else ++ ok_(__FILE__, line)(ace->Mask == mask, ++ "Administators Group ACE has unexpected mask (0x%x != 0x%x)\n", ++ ace->Mask, mask); } + } + +@@ -3262,7 +3274,7 @@ static void test_CreateDirectoryA(void) + } + ok(!error, "GetNamedSecurityInfo failed with error %d\n", error); + test_inherited_dacl(pDacl, admin_sid, user_sid, OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE, +- 0x1f01ff, FALSE, TRUE, TRUE, __LINE__); ++ 0x1f01ff, FALSE, FALSE, FALSE, TRUE, __LINE__); LocalFree(pSD); -@@ -3384,23 +3384,22 @@ static void test_GetNamedSecurityInfoA(void) + /* Test inheritance of ACLs in CreateFile without security descriptor */ +@@ -3278,7 +3290,7 @@ static void test_CreateDirectoryA(void) + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "Failed to get permissions on file\n"); + test_inherited_dacl(pDacl, admin_sid, user_sid, INHERITED_ACE, +- 0x1f01ff, TRUE, TRUE, TRUE, __LINE__); ++ 0x1f01ff, TRUE, TRUE, TRUE, FALSE, __LINE__); + LocalFree(pSD); + CloseHandle(hTemp); + +@@ -3352,7 +3364,7 @@ static void test_CreateDirectoryA(void) + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "Failed to get permissions on file\n"); + test_inherited_dacl(pDacl, admin_sid, user_sid, INHERITED_ACE, +- 0x1f01ff, TRUE, TRUE, TRUE, __LINE__); ++ 0x1f01ff, TRUE, TRUE, TRUE, FALSE, __LINE__); + LocalFree(pSD); + CloseHandle(hTemp); + +@@ -3581,23 +3593,22 @@ static void test_GetNamedSecurityInfoA(void) bret = pGetAce(pDacl, 0, (VOID **)&ace); ok(bret, "Failed to get Current User ACE.\n"); bret = EqualSid(&ace->SidStart, user_sid); @@ -80,7 +117,7 @@ index b44496a..02094a4 100644 } LocalFree(pSD); HeapFree(GetProcessHeap(), 0, user); -@@ -4050,22 +4049,22 @@ static void test_GetSecurityInfo(void) +@@ -4247,22 +4258,22 @@ static void test_GetSecurityInfo(void) bret = pGetAce(pDacl, 0, (VOID **)&ace); ok(bret, "Failed to get Current User ACE.\n"); bret = EqualSid(&ace->SidStart, user_sid); @@ -110,10 +147,10 @@ index b44496a..02094a4 100644 LocalFree(pSD); CloseHandle(obj); diff --git a/server/file.c b/server/file.c -index 72d6d95..ff51b73 100644 +index a1455ff..e84331d 100644 --- a/server/file.c +++ b/server/file.c -@@ -499,6 +499,25 @@ struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID +@@ -503,6 +503,25 @@ struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID return sd; } @@ -139,7 +176,7 @@ index 72d6d95..ff51b73 100644 struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode_t *mode, uid_t *uid ) { -@@ -514,9 +533,10 @@ struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode +@@ -518,9 +537,10 @@ struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode (st.st_uid == *uid)) return obj->sd; @@ -154,5 +191,5 @@ index 72d6d95..ff51b73 100644 *mode = st.st_mode; -- -1.7.9.5 +2.3.3 diff --git a/patches/server-Stored_ACLs/0006-server-Convert-return-of-file-security-masks-with-ge.patch b/patches/server-Stored_ACLs/0006-server-Convert-return-of-file-security-masks-with-ge.patch index 77263606..beb2219a 100644 --- a/patches/server-Stored_ACLs/0006-server-Convert-return-of-file-security-masks-with-ge.patch +++ b/patches/server-Stored_ACLs/0006-server-Convert-return-of-file-security-masks-with-ge.patch @@ -1,41 +1,93 @@ -From 9364028096235e2f64b9fe070170b5e4bb2311ca Mon Sep 17 00:00:00 2001 +From 3779a55c15d92da1974ff1520e20bc5accc8e4b6 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Fri, 18 Apr 2014 14:05:32 -0600 Subject: server: Convert return of file security masks with generic access mappings. (try 7) --- - dlls/advapi32/tests/security.c | 24 ++++++++++++------------ - server/file.c | 22 ++++++++++++++++++++++ - 2 files changed, 34 insertions(+), 12 deletions(-) + dlls/advapi32/tests/security.c | 48 ++++++++++++++++-------------------------- + server/file.c | 22 +++++++++++++++++++ + 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c -index 02094a4..82c0639 100644 +index 3f97a82..a530a3f 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c -@@ -3196,8 +3196,8 @@ static void test_CreateDirectoryA(void) - ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE), - "Current User ACE has unexpected flags (0x%x != 0x03)\n", - ((ACE_HEADER *)ace)->AceFlags); -- todo_wine ok(ace->Mask == 0x1f01ff, -- "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n", ace->Mask); -+ ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%x != 0x1f01ff)\n", -+ ace->Mask); +@@ -3109,7 +3109,7 @@ static void get_nt_pathW(const char *name, UNICODE_STRING *nameW) + } + + static void test_inherited_dacl(PACL dacl, PSID admin_sid, PSID user_sid, DWORD flags, DWORD mask, +- BOOL todo_count, BOOL todo_sid, BOOL todo_flags, BOOL todo_mask, int line) ++ BOOL todo_count, BOOL todo_sid, BOOL todo_flags, int line) + { + ACL_SIZE_INFORMATION acl_size; + ACCESS_ALLOWED_ACE *ace; +@@ -3150,15 +3150,9 @@ static void test_inherited_dacl(PACL dacl, PSID admin_sid, PSID user_sid, DWORD + "Current User ACE has unexpected flags (0x%x != 0x%x)\n", + ((ACE_HEADER *)ace)->AceFlags, flags); + +- if (todo_mask) +- todo_wine +- ok_(__FILE__, line)(ace->Mask == mask, +- "Current User ACE has unexpected mask (0x%x != 0x%x)\n", +- ace->Mask, mask); +- else +- ok_(__FILE__, line)(ace->Mask == mask, +- "Current User ACE has unexpected mask (0x%x != 0x%x)\n", +- ace->Mask, mask); ++ ok_(__FILE__, line)(ace->Mask == mask, ++ "Current User ACE has unexpected mask (0x%x != 0x%x)\n", ++ ace->Mask, mask); } if (acl_size.AceCount > 1) { -@@ -3208,8 +3208,8 @@ static void test_CreateDirectoryA(void) - ok(((ACE_HEADER *)ace)->AceFlags == (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE), - "Administators Group ACE has unexpected flags (0x%x != 0x03)\n", - ((ACE_HEADER *)ace)->AceFlags); -- todo_wine ok(ace->Mask == 0x1f01ff, -- "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n", ace->Mask); -+ ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%x != 0x1f01ff)\n", -+ ace->Mask); +@@ -3182,15 +3176,9 @@ static void test_inherited_dacl(PACL dacl, PSID admin_sid, PSID user_sid, DWORD + "Administators Group ACE has unexpected flags (0x%x != 0x%x)\n", + ((ACE_HEADER *)ace)->AceFlags, flags); + +- if (todo_mask) +- todo_wine +- ok_(__FILE__, line)(ace->Mask == mask, +- "Administators Group ACE has unexpected mask (0x%x != 0x%x)\n", +- ace->Mask, mask); +- else +- ok_(__FILE__, line)(ace->Mask == mask, +- "Administators Group ACE has unexpected mask (0x%x != 0x%x)\n", +- ace->Mask, mask); ++ ok_(__FILE__, line)(ace->Mask == mask, ++ "Administators Group ACE has unexpected mask (0x%x != 0x%x)\n", ++ ace->Mask, mask); } + } + +@@ -3274,7 +3262,7 @@ static void test_CreateDirectoryA(void) + } + ok(!error, "GetNamedSecurityInfo failed with error %d\n", error); + test_inherited_dacl(pDacl, admin_sid, user_sid, OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE, +- 0x1f01ff, FALSE, FALSE, FALSE, TRUE, __LINE__); ++ 0x1f01ff, FALSE, FALSE, FALSE, __LINE__); LocalFree(pSD); -@@ -3387,8 +3387,8 @@ static void test_GetNamedSecurityInfoA(void) + /* Test inheritance of ACLs in CreateFile without security descriptor */ +@@ -3290,7 +3278,7 @@ static void test_CreateDirectoryA(void) + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "Failed to get permissions on file\n"); + test_inherited_dacl(pDacl, admin_sid, user_sid, INHERITED_ACE, +- 0x1f01ff, TRUE, TRUE, TRUE, FALSE, __LINE__); ++ 0x1f01ff, TRUE, TRUE, TRUE, __LINE__); + LocalFree(pSD); + CloseHandle(hTemp); + +@@ -3364,7 +3352,7 @@ static void test_CreateDirectoryA(void) + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "Failed to get permissions on file\n"); + test_inherited_dacl(pDacl, admin_sid, user_sid, INHERITED_ACE, +- 0x1f01ff, TRUE, TRUE, TRUE, FALSE, __LINE__); ++ 0x1f01ff, TRUE, TRUE, TRUE, __LINE__); + LocalFree(pSD); + CloseHandle(hTemp); + +@@ -3596,8 +3584,8 @@ static void test_GetNamedSecurityInfoA(void) ok(bret, "Current User ACE != Current User SID.\n"); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Current User ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); @@ -46,7 +98,7 @@ index 02094a4..82c0639 100644 } if (acl_size.AceCount > 1) { -@@ -3398,8 +3398,8 @@ static void test_GetNamedSecurityInfoA(void) +@@ -3607,8 +3595,8 @@ static void test_GetNamedSecurityInfoA(void) ok(bret || broken(!bret) /* win2k */, "Administators Group ACE != Administators Group SID.\n"); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Administators Group ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); @@ -57,7 +109,7 @@ index 02094a4..82c0639 100644 } LocalFree(pSD); HeapFree(GetProcessHeap(), 0, user); -@@ -4052,8 +4052,8 @@ static void test_GetSecurityInfo(void) +@@ -4261,8 +4249,8 @@ static void test_GetSecurityInfo(void) ok(bret, "Current User ACE != Current User SID.\n"); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Current User ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); @@ -68,7 +120,7 @@ index 02094a4..82c0639 100644 } if (acl_size.AceCount > 1) { -@@ -4063,8 +4063,8 @@ static void test_GetSecurityInfo(void) +@@ -4272,8 +4260,8 @@ static void test_GetSecurityInfo(void) ok(bret, "Administators Group ACE != Administators Group SID.\n"); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Administators Group ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); @@ -80,10 +132,10 @@ index 02094a4..82c0639 100644 LocalFree(pSD); CloseHandle(obj); diff --git a/server/file.c b/server/file.c -index ff72273..38eda5c 100644 +index e84331d..b6435d1 100644 --- a/server/file.c +++ b/server/file.c -@@ -521,6 +521,27 @@ struct security_descriptor *get_xattr_sd( int fd ) +@@ -522,6 +522,27 @@ struct security_descriptor *get_xattr_sd( int fd ) return sd; } @@ -111,7 +163,7 @@ index ff72273..38eda5c 100644 struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode_t *mode, uid_t *uid ) { -@@ -537,6 +558,7 @@ struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode +@@ -538,6 +559,7 @@ struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode return obj->sd; sd = get_xattr_sd( unix_fd ); @@ -120,5 +172,5 @@ index ff72273..38eda5c 100644 security_unix_uid_to_sid( st.st_uid ), token_get_primary_group( current->process->token )); -- -1.7.9.5 +2.3.3