[RTL]
authorThomas Faber <thomas.faber@reactos.org>
Sun, 22 May 2016 22:11:54 +0000 (22:11 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Sun, 22 May 2016 22:11:54 +0000 (22:11 +0000)
- Return the ACE pointer from RtlFirstFreeAce also if it is at the end of the ACL buffer.
CORE-11304 #resolve

svn path=/trunk/; revision=71382

reactos/sdk/lib/rtl/acl.c
rostests/apitests/ntdll/CMakeLists.txt
rostests/apitests/ntdll/RtlDeleteAce.c [new file with mode: 0644]
rostests/apitests/ntdll/RtlFirstFreeAce.c [new file with mode: 0644]
rostests/apitests/ntdll/testlist.c

index a29ab58..18fb3a6 100644 (file)
@@ -41,7 +41,7 @@ RtlFirstFreeAce(IN PACL Acl,
     }
 
     /* If the last spot is empty and still valid, return it */
-    if ((ULONG_PTR)Current < AclEnd) *FirstFreeAce = Current;
+    if ((ULONG_PTR)Current <= AclEnd) *FirstFreeAce = Current;
     return TRUE;
 }
 
index cbd19aa..ce42c7b 100644 (file)
@@ -22,11 +22,13 @@ list(APPEND SOURCE
     RtlAllocateHeap.c
     RtlBitmap.c
     RtlCopyMappedMemory.c
+    RtlDeleteAce.c
     RtlDetermineDosPathNameType.c
     RtlDoesFileExists.c
     RtlDosPathNameToNtPathName_U.c
     RtlDosSearchPath_U.c
     RtlDosSearchPath_Ustr.c
+    RtlFirstFreeAce.c
     RtlGenerate8dot3Name.c
     RtlGetFullPathName_U.c
     RtlGetFullPathName_Ustr.c
diff --git a/rostests/apitests/ntdll/RtlDeleteAce.c b/rostests/apitests/ntdll/RtlDeleteAce.c
new file mode 100644 (file)
index 0000000..fbf4313
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * PROJECT:         ReactOS API tests
+ * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
+ * PURPOSE:         Test for RtlDeleteAce
+ * PROGRAMMERS:     Thomas Faber <thomas.faber@reactos.org>
+ */
+
+#include <apitest.h>
+#include <ndk/mmfuncs.h>
+#include <ndk/rtlfuncs.h>
+
+static
+PVOID
+AllocateGuarded(
+    _In_ SIZE_T SizeRequested)
+{
+    NTSTATUS Status;
+    SIZE_T Size = PAGE_ROUND_UP(SizeRequested + PAGE_SIZE);
+    PVOID VirtualMemory = NULL;
+    PCHAR StartOfBuffer;
+
+    Status = NtAllocateVirtualMemory(NtCurrentProcess(), &VirtualMemory, 0, &Size, MEM_RESERVE, PAGE_NOACCESS);
+
+    if (!NT_SUCCESS(Status))
+        return NULL;
+
+    Size -= PAGE_SIZE;
+    if (Size)
+    {
+        Status = NtAllocateVirtualMemory(NtCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
+        if (!NT_SUCCESS(Status))
+        {
+            Size = 0;
+            Status = NtFreeVirtualMemory(NtCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
+            ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
+            return NULL;
+        }
+    }
+
+    StartOfBuffer = VirtualMemory;
+    StartOfBuffer += Size - SizeRequested;
+
+    return StartOfBuffer;
+}
+
+static
+VOID
+FreeGuarded(
+    _In_ PVOID Pointer)
+{
+    NTSTATUS Status;
+    PVOID VirtualMemory = (PVOID)PAGE_ROUND_DOWN((SIZE_T)Pointer);
+    SIZE_T Size = 0;
+
+    Status = NtFreeVirtualMemory(NtCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
+    ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
+}
+
+static
+PACL
+MakeAcl(
+    _In_ ULONG AceCount,
+    ...)
+{
+    PACL Acl;
+    PACE_HEADER AceHeader;
+    ULONG AclSize;
+    ULONG AceSizes[10];
+    ULONG i;
+    va_list Args;
+
+    ASSERT(AceCount <= RTL_NUMBER_OF(AceSizes));
+    AclSize = sizeof(ACL);
+    va_start(Args, AceCount);
+    for (i = 0; i < AceCount; i++)
+    {
+        AceSizes[i] = va_arg(Args, int);
+        AclSize += AceSizes[i];
+    }
+    va_end(Args);
+
+    Acl = AllocateGuarded(AclSize);
+    if (!Acl)
+    {
+        skip("Failed to allocate %lu bytes\n", AclSize);
+        return NULL;
+    }
+
+    Acl->AclRevision = ACL_REVISION;
+    Acl->Sbz1 = 0;
+    Acl->AclSize = AclSize;
+    Acl->AceCount = AceCount;
+    Acl->Sbz2 = 0;
+
+    AceHeader = (PACE_HEADER)(Acl + 1);
+    for (i = 0; i < AceCount; i++)
+    {
+        AceHeader->AceType = 0;
+        AceHeader->AceFlags = 0;
+        AceHeader->AceSize = AceSizes[i];
+        AceHeader = (PACE_HEADER)((PCHAR)AceHeader + AceHeader->AceSize);
+    }
+
+    return Acl;
+}
+
+START_TEST(RtlDeleteAce)
+{
+    PACL Acl;
+    PACCESS_ALLOWED_ACE Ace;
+    ULONG AceSize;
+    PISID Sid;
+    NTSTATUS Status;
+    int i;
+
+    Acl = MakeAcl(0);
+    if (Acl)
+    {
+        ok(RtlValidAcl(Acl), "Acl is invalid\n");
+
+        /* There is no first ACE -- should stay untouched */
+        Status = RtlDeleteAce(Acl, 0);
+        ok(Status == STATUS_INVALID_PARAMETER, "Status = %lx\n", Status);
+        ok(Acl->AclSize == sizeof(ACL), "AclSize = %u\n", Acl->AclSize);
+        ok(Acl->AceCount == 0, "AceCount = %u\n", Acl->AceCount);
+
+        /* Index -1 -- should stay untouched */
+        Status = RtlDeleteAce(Acl, 0xFFFFFFFF);
+        ok(Status == STATUS_INVALID_PARAMETER, "Status = %lx\n", Status);
+        FreeGuarded(Acl);
+    }
+
+    AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority);
+    Acl = MakeAcl(1, (int)AceSize);
+    if (Acl)
+    {
+        Ace = (PACCESS_ALLOWED_ACE)(Acl + 1);
+        Ace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
+        Sid = (PISID)&Ace->SidStart;
+        Sid->Revision = SID_REVISION;
+        Sid->SubAuthorityCount = 0;
+        RtlZeroMemory(&Sid->IdentifierAuthority, sizeof(Sid->IdentifierAuthority));
+
+        ok(RtlValidAcl(Acl), "Acl is invalid\n");
+
+        /* Out of bounds delete -- should stay untouched */
+        Status = RtlDeleteAce(Acl, 1);
+        ok(Status == STATUS_INVALID_PARAMETER, "Status = %lx\n", Status);
+        ok(Acl->AclSize == sizeof(ACL) + AceSize, "AclSize = %u\n", Acl->AclSize);
+        ok(Acl->AceCount == 1, "AceCount = %u\n", Acl->AceCount);
+        ok(Ace->Header.AceSize == AceSize, "AceSize = %u\n", Ace->Header.AceSize);
+
+        /* Index -1 -- should stay untouched */
+        Status = RtlDeleteAce(Acl, 0xFFFFFFFF);
+        ok(Status == STATUS_INVALID_PARAMETER, "Status = %lx\n", Status);
+        ok(Acl->AclSize == sizeof(ACL) + AceSize, "AclSize = %u\n", Acl->AclSize);
+        ok(Acl->AceCount == 1, "AceCount = %u\n", Acl->AceCount);
+        ok(Ace->Header.AceSize == AceSize, "AceSize = %u\n", Ace->Header.AceSize);
+
+        /* Delete the first (and only) ACE */
+        Status = RtlDeleteAce(Acl, 0);
+        ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
+        ok(Acl->AclSize == sizeof(ACL) + AceSize, "AclSize = %u\n", Acl->AclSize);
+        ok(Acl->AceCount == 0, "AceCount = %u\n", Acl->AceCount);
+        ok(Ace->Header.AceSize == 0, "AceSize = %u\n", Ace->Header.AceSize);
+        FreeGuarded(Acl);
+    }
+
+    AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority[1]);
+    Acl = MakeAcl(4, (int)AceSize, (int)AceSize + 4, (int)AceSize + 8, (int)AceSize + 12);
+    if (Acl)
+    {
+        Ace = (PACCESS_ALLOWED_ACE)(Acl + 1);
+        for (i = 0; i < 4; i++)
+        {
+            Ace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
+            Sid = (PISID)&Ace->SidStart;
+            Sid->Revision = SID_REVISION;
+            Sid->SubAuthorityCount = 0;
+            RtlZeroMemory(&Sid->IdentifierAuthority, sizeof(Sid->IdentifierAuthority));
+            Ace = (PACCESS_ALLOWED_ACE)((PCHAR)Ace + Ace->Header.AceSize);
+        }
+
+        ok(RtlValidAcl(Acl), "Acl is invalid\n");
+
+        /* Out of bounds delete -- should stay untouched */
+        Status = RtlDeleteAce(Acl, 4);
+        ok(Status == STATUS_INVALID_PARAMETER, "Status = %lx\n", Status);
+        ok(Acl->AclSize == sizeof(ACL) + 4 * AceSize + 24, "AclSize = %u\n", Acl->AclSize);
+        ok(Acl->AceCount == 4, "AceCount = %u\n", Acl->AceCount);
+        Ace = (PACCESS_ALLOWED_ACE)(Acl + 1);
+        ok(Ace->Header.AceSize == AceSize, "AceSize = %u\n", Ace->Header.AceSize);
+        Ace = (PACCESS_ALLOWED_ACE)((PCHAR)Ace + Ace->Header.AceSize);
+        ok(Ace->Header.AceSize == AceSize + 4, "AceSize = %u\n", Ace->Header.AceSize);
+        Ace = (PACCESS_ALLOWED_ACE)((PCHAR)Ace + Ace->Header.AceSize);
+        ok(Ace->Header.AceSize == AceSize + 8, "AceSize = %u\n", Ace->Header.AceSize);
+        Ace = (PACCESS_ALLOWED_ACE)((PCHAR)Ace + Ace->Header.AceSize);
+        ok(Ace->Header.AceSize == AceSize + 12, "AceSize = %u\n", Ace->Header.AceSize);
+
+        /* Index -1 -- should stay untouched */
+        Status = RtlDeleteAce(Acl, 0xFFFFFFFF);
+        ok(Status == STATUS_INVALID_PARAMETER, "Status = %lx\n", Status);
+        ok(Acl->AclSize == sizeof(ACL) + 4 * AceSize + 24, "AclSize = %u\n", Acl->AclSize);
+        ok(Acl->AceCount == 4, "AceCount = %u\n", Acl->AceCount);
+        Ace = (PACCESS_ALLOWED_ACE)(Acl + 1);
+        ok(Ace->Header.AceSize == AceSize, "AceSize = %u\n", Ace->Header.AceSize);
+        Ace = (PACCESS_ALLOWED_ACE)((PCHAR)Ace + Ace->Header.AceSize);
+        ok(Ace->Header.AceSize == AceSize + 4, "AceSize = %u\n", Ace->Header.AceSize);
+        Ace = (PACCESS_ALLOWED_ACE)((PCHAR)Ace + Ace->Header.AceSize);
+        ok(Ace->Header.AceSize == AceSize + 8, "AceSize = %u\n", Ace->Header.AceSize);
+        Ace = (PACCESS_ALLOWED_ACE)((PCHAR)Ace + Ace->Header.AceSize);
+        ok(Ace->Header.AceSize == AceSize + 12, "AceSize = %u\n", Ace->Header.AceSize);
+
+        /* Delete the last ACE */
+        Status = RtlDeleteAce(Acl, 3);
+        ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
+        ok(Acl->AclSize == sizeof(ACL) + 4 * AceSize + 24, "AclSize = %u\n", Acl->AclSize);
+        ok(Acl->AceCount == 3, "AceCount = %u\n", Acl->AceCount);
+        Ace = (PACCESS_ALLOWED_ACE)(Acl + 1);
+        ok(Ace->Header.AceSize == AceSize, "AceSize = %u\n", Ace->Header.AceSize);
+        Ace = (PACCESS_ALLOWED_ACE)((PCHAR)Ace + Ace->Header.AceSize);
+        ok(Ace->Header.AceSize == AceSize + 4, "AceSize = %u\n", Ace->Header.AceSize);
+        Ace = (PACCESS_ALLOWED_ACE)((PCHAR)Ace + Ace->Header.AceSize);
+        ok(Ace->Header.AceSize == AceSize + 8, "AceSize = %u\n", Ace->Header.AceSize);
+        Ace = (PACCESS_ALLOWED_ACE)((PCHAR)Ace + Ace->Header.AceSize);
+        ok(Ace->Header.AceSize == 0, "AceSize = %u\n", Ace->Header.AceSize);
+
+        /* Delete the second ACE */
+        Status = RtlDeleteAce(Acl, 1);
+        ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
+        ok(Acl->AclSize == sizeof(ACL) + 4 * AceSize + 24, "AclSize = %u\n", Acl->AclSize);
+        ok(Acl->AceCount == 2, "AceCount = %u\n", Acl->AceCount);
+        Ace = (PACCESS_ALLOWED_ACE)(Acl + 1);
+        ok(Ace->Header.AceSize == AceSize, "AceSize = %u\n", Ace->Header.AceSize);
+        Ace = (PACCESS_ALLOWED_ACE)((PCHAR)Ace + Ace->Header.AceSize);
+        ok(Ace->Header.AceSize == AceSize + 8, "AceSize = %u\n", Ace->Header.AceSize);
+        Ace = (PACCESS_ALLOWED_ACE)((PCHAR)Ace + Ace->Header.AceSize);
+        ok(Ace->Header.AceSize == 0, "AceSize = %u\n", Ace->Header.AceSize);
+
+        /* Delete the first ACE */
+        Status = RtlDeleteAce(Acl, 0);
+        ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
+        ok(Acl->AclSize == sizeof(ACL) + 4 * AceSize + 24, "AclSize = %u\n", Acl->AclSize);
+        ok(Acl->AceCount == 1, "AceCount = %u\n", Acl->AceCount);
+        Ace = (PACCESS_ALLOWED_ACE)(Acl + 1);
+        ok(Ace->Header.AceSize == AceSize + 8, "AceSize = %u\n", Ace->Header.AceSize);
+        Ace = (PACCESS_ALLOWED_ACE)((PCHAR)Ace + Ace->Header.AceSize);
+        ok(Ace->Header.AceSize == 0, "AceSize = %u\n", Ace->Header.AceSize);
+
+        /* Delete the remaining ACE */
+        Status = RtlDeleteAce(Acl, 0);
+        ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
+        ok(Acl->AclSize == sizeof(ACL) + 4 * AceSize + 24, "AclSize = %u\n", Acl->AclSize);
+        ok(Acl->AceCount == 0, "AceCount = %u\n", Acl->AceCount);
+        Ace = (PACCESS_ALLOWED_ACE)(Acl + 1);
+        ok(Ace->Header.AceSize == 0, "AceSize = %u\n", Ace->Header.AceSize);
+
+        FreeGuarded(Acl);
+    }
+}
diff --git a/rostests/apitests/ntdll/RtlFirstFreeAce.c b/rostests/apitests/ntdll/RtlFirstFreeAce.c
new file mode 100644 (file)
index 0000000..ebe12e0
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * PROJECT:         ReactOS API tests
+ * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
+ * PURPOSE:         Test for RtlFirstFreeAce
+ * PROGRAMMERS:     Thomas Faber <thomas.faber@reactos.org>
+ */
+
+#include <apitest.h>
+#include <ndk/mmfuncs.h>
+#include <ndk/rtlfuncs.h>
+
+static
+PVOID
+AllocateGuarded(
+    _In_ SIZE_T SizeRequested)
+{
+    NTSTATUS Status;
+    SIZE_T Size = PAGE_ROUND_UP(SizeRequested + PAGE_SIZE);
+    PVOID VirtualMemory = NULL;
+    PCHAR StartOfBuffer;
+
+    Status = NtAllocateVirtualMemory(NtCurrentProcess(), &VirtualMemory, 0, &Size, MEM_RESERVE, PAGE_NOACCESS);
+
+    if (!NT_SUCCESS(Status))
+        return NULL;
+
+    Size -= PAGE_SIZE;
+    if (Size)
+    {
+        Status = NtAllocateVirtualMemory(NtCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
+        if (!NT_SUCCESS(Status))
+        {
+            Size = 0;
+            Status = NtFreeVirtualMemory(NtCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
+            ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
+            return NULL;
+        }
+    }
+
+    StartOfBuffer = VirtualMemory;
+    StartOfBuffer += Size - SizeRequested;
+
+    return StartOfBuffer;
+}
+
+static
+VOID
+FreeGuarded(
+    _In_ PVOID Pointer)
+{
+    NTSTATUS Status;
+    PVOID VirtualMemory = (PVOID)PAGE_ROUND_DOWN((SIZE_T)Pointer);
+    SIZE_T Size = 0;
+
+    Status = NtFreeVirtualMemory(NtCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
+    ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
+}
+
+static
+PACL
+MakeAcl(
+    _In_ ULONG AceCount,
+    ...)
+{
+    PACL Acl;
+    PACE_HEADER AceHeader;
+    ULONG AclSize;
+    ULONG AceSizes[10];
+    ULONG i;
+    va_list Args;
+
+    ASSERT(AceCount <= RTL_NUMBER_OF(AceSizes));
+    AclSize = sizeof(ACL);
+    va_start(Args, AceCount);
+    for (i = 0; i < AceCount; i++)
+    {
+        AceSizes[i] = va_arg(Args, int);
+        AclSize += AceSizes[i];
+    }
+    va_end(Args);
+
+    Acl = AllocateGuarded(AclSize);
+    if (!Acl)
+    {
+        skip("Failed to allocate %lu bytes\n", AclSize);
+        return NULL;
+    }
+
+    Acl->AclRevision = ACL_REVISION;
+    Acl->Sbz1 = 0;
+    Acl->AclSize = AclSize;
+    Acl->AceCount = AceCount;
+    Acl->Sbz2 = 0;
+
+    AceHeader = (PACE_HEADER)(Acl + 1);
+    for (i = 0; i < AceCount; i++)
+    {
+        AceHeader->AceType = 0;
+        AceHeader->AceFlags = 0;
+        AceHeader->AceSize = AceSizes[i];
+        AceHeader = (PACE_HEADER)((PCHAR)AceHeader + AceHeader->AceSize);
+    }
+
+    return Acl;
+}
+
+START_TEST(RtlFirstFreeAce)
+{
+    PACL Acl;
+    PACE FirstAce;
+    BOOLEAN Found;
+
+    Acl = MakeAcl(0);
+    if (Acl)
+    {
+        /* Simple empty ACL */
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == TRUE, "Found = %u\n", Found);
+        ok(FirstAce == (PACE)(Acl + 1), "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        /* Not enough space */
+        Acl->AclSize = sizeof(ACL) - 1;
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == TRUE, "Found = %u\n", Found);
+        ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        /* Invalid values for all the other fields */
+        Acl->AclRevision = 76;
+        Acl->Sbz1 = 0x55;
+        Acl->AclSize = sizeof(ACL);
+        Acl->Sbz2 = 0x55;
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == TRUE, "Found = %u\n", Found);
+        ok(FirstAce == (PACE)(Acl + 1), "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        FreeGuarded(Acl);
+    }
+
+    Acl = MakeAcl(1, (int)sizeof(ACE_HEADER));
+    if (Acl)
+    {
+        /* ACL with one ACE */
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == TRUE, "Found = %u\n", Found);
+        ok(FirstAce == (PACE)((PACE_HEADER)(Acl + 1) + 1), "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        /* The one ACE doesn't actually fit */
+        Acl->AclSize = sizeof(ACL);
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == FALSE, "Found = %u\n", Found);
+        ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        /* Only the first byte fits */
+        Acl->AclSize = sizeof(ACL) + 1;
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == TRUE, "Found = %u\n", Found);
+        ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        /* Until we cover the whole size we get NULL */
+        Acl->AclSize = sizeof(ACL) + sizeof(ACE_HEADER) - 1;
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == TRUE, "Found = %u\n", Found);
+        ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        FreeGuarded(Acl);
+    }
+
+    /* Same but bigger */
+    Acl = MakeAcl(1, (int)sizeof(ACE_HEADER) + 4);
+    if (Acl)
+    {
+        /* ACL with one ACE */
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == TRUE, "Found = %u\n", Found);
+        ok(FirstAce == (PACE)((PCHAR)(Acl + 1) + sizeof(ACE_HEADER) + 4), "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        /* The one ACE doesn't actually fit */
+        Acl->AclSize = sizeof(ACL);
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == FALSE, "Found = %u\n", Found);
+        ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        /* Only the first byte fits */
+        Acl->AclSize = sizeof(ACL) + 1;
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == TRUE, "Found = %u\n", Found);
+        ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        /* Until we cover the whole size we get NULL */
+        Acl->AclSize = sizeof(ACL) + sizeof(ACE_HEADER) - 3;
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == TRUE, "Found = %u\n", Found);
+        ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        FreeGuarded(Acl);
+    }
+
+    Acl = MakeAcl(4, (int)sizeof(ACE_HEADER), (int)sizeof(ACE_HEADER), (int)sizeof(ACCESS_ALLOWED_ACE), (int)sizeof(ACCESS_ALLOWED_ACE));
+    if (Acl)
+    {
+        /* ACL with one ACE */
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == TRUE, "Found = %u\n", Found);
+        ok(FirstAce == (PACE)((PCHAR)(Acl + 1) + 2 * sizeof(ACE_HEADER) + 2 * sizeof(ACCESS_ALLOWED_ACE)), "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        /* One less gives us NULL */
+        Acl->AclSize = sizeof(ACL) + 2 * sizeof(ACE_HEADER) + 2 * sizeof(ACCESS_ALLOWED_ACE) - 1;
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == TRUE, "Found = %u\n", Found);
+        ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        /* One ACE less also gives us FALSE */
+        Acl->AclSize = sizeof(ACL) + 2 * sizeof(ACE_HEADER) + sizeof(ACCESS_ALLOWED_ACE);
+        FirstAce = InvalidPointer;
+        Found = RtlFirstFreeAce(Acl, &FirstAce);
+        ok(Found == FALSE, "Found = %u\n", Found);
+        ok(FirstAce == NULL, "FirstAce = %p (Acl was %p)\n", FirstAce, Acl);
+
+        FreeGuarded(Acl);
+    }
+}
index f13f249..1b4c547 100644 (file)
@@ -26,11 +26,13 @@ extern void func_NtSystemInformation(void);
 extern void func_RtlAllocateHeap(void);
 extern void func_RtlBitmap(void);
 extern void func_RtlCopyMappedMemory(void);
+extern void func_RtlDeleteAce(void);
 extern void func_RtlDetermineDosPathNameType(void);
 extern void func_RtlDoesFileExists(void);
 extern void func_RtlDosPathNameToNtPathName_U(void);
 extern void func_RtlDosSearchPath_U(void);
 extern void func_RtlDosSearchPath_Ustr(void);
+extern void func_RtlFirstFreeAce(void);
 extern void func_RtlGenerate8dot3Name(void);
 extern void func_RtlGetFullPathName_U(void);
 extern void func_RtlGetFullPathName_Ustr(void);
@@ -69,11 +71,13 @@ const struct test winetest_testlist[] =
     { "RtlAllocateHeap",                func_RtlAllocateHeap },
     { "RtlBitmapApi",                   func_RtlBitmap },
     { "RtlCopyMappedMemory",            func_RtlCopyMappedMemory },
+    { "RtlDeleteAce",                   func_RtlDeleteAce },
     { "RtlDetermineDosPathNameType",    func_RtlDetermineDosPathNameType },
     { "RtlDoesFileExists",              func_RtlDoesFileExists },
     { "RtlDosPathNameToNtPathName_U",   func_RtlDosPathNameToNtPathName_U },
     { "RtlDosSearchPath_U",             func_RtlDosSearchPath_U },
     { "RtlDosSearchPath_Ustr",          func_RtlDosSearchPath_Ustr },
+    { "RtlFirstFreeAce",                func_RtlFirstFreeAce },
     { "RtlGenerate8dot3Name",           func_RtlGenerate8dot3Name },
     { "RtlGetFullPathName_U",           func_RtlGetFullPathName_U },
     { "RtlGetFullPathName_Ustr",        func_RtlGetFullPathName_Ustr },