[RTL]: Document and flesh out Boot Status Data (BSD) API/Structures
authorAlex Ionescu <aionescu@gmail.com>
Sun, 4 Feb 2018 17:33:32 +0000 (09:33 -0800)
committerAlex Ionescu <aionescu@gmail.com>
Sun, 4 Feb 2018 17:33:32 +0000 (09:33 -0800)
[NDK]: Document latest RTL_BSD_DATA as of RS3 based on ext.dll WinDBG
extension "!blackboxbsd" which outputs the entire structure field by
field :).
[NDK]: Update RTL_BSD_ITEM_TYPE thanks to ole32 symbols
[RTL]: Move system volume APIs to sysvol.c
[RTL]: Fill out BsdItemTable based on actual field offsets/sizes and not
hardcoded magic numbers which we won't ask where they came from.
[RTL]: Make RtlCreateBootStatusDataFile use an appropriate structure for
initializing the buffer instead of "UCHAR Buffer[12] = {0xC,0,0,0,
1,0,0,0, 1, 0x1e, 1, 0};" which appears like magic knowledge.
[RTL]: Rename "WriteMode" to "Read" in RtlGetSetBootStatusData since
it's much less confusing.
[RTL]: Some formatting fixes, SAL updates.

sdk/include/ndk/rtltypes.h
sdk/lib/rtl/CMakeLists.txt
sdk/lib/rtl/bootdata.c
sdk/lib/rtl/sysvol.c [new file with mode: 0644]

index 0abde3e..1371f4c 100644 (file)
@@ -414,9 +414,6 @@ C_ASSERT(FIELD_OFFSET(LARGE_INTEGER, LowPart) == 0);
 #define RTL_CONSTANT_LARGE_INTEGER(quad_part) { { (quad_part), (quad_part)>>32 } }
 #define RTL_MAKE_LARGE_INTEGER(low_part, high_part) { { (low_part), (high_part) } }
 
-
-#ifdef NTOS_MODE_USER
-
 //
 // Boot Status Data Field Types
 //
@@ -428,9 +425,20 @@ typedef enum _RTL_BSD_ITEM_TYPE
     RtlBsdItemAabTimeout,
     RtlBsdItemBootGood,
     RtlBsdItemBootShutdown,
+    RtlBsdSleepInProgress,
+    RtlBsdPowerTransition,
+    RtlBsdItemBootAttemptCount,
+    RtlBsdItemBootCheckpoint,
+    RtlBsdItemBootId,
+    RtlBsdItemShutdownBootId,
+    RtlBsdItemReportedAbnormalShutdownBootId,
+    RtlBsdItemErrorInfo,
+    RtlBsdItemPowerButtonPressInfo,
+    RtlBsdItemChecksum,
     RtlBsdItemMax
 } RTL_BSD_ITEM_TYPE, *PRTL_BSD_ITEM_TYPE;
 
+#ifdef NTOS_MODE_USER
 //
 // Table and Compare result types
 //
@@ -1238,6 +1246,92 @@ typedef struct _RTL_HANDLE_TABLE
     PRTL_HANDLE_TABLE_ENTRY MaxReservedHandles;
 } RTL_HANDLE_TABLE, *PRTL_HANDLE_TABLE;
 
+//
+// RTL Boot Status Data Item
+//
+typedef struct _RTL_BSD_ITEM
+{
+    RTL_BSD_ITEM_TYPE Type;
+    PVOID DataBuffer;
+    ULONG DataLength;
+} RTL_BSD_ITEM, *PRTL_BSD_ITEM;
+
+//
+// Data Sub-Structures for "bootstat.dat" RTL Data File
+//
+typedef struct _RTL_BSD_DATA_POWER_TRANSITION
+{
+    LARGE_INTEGER PowerButtonTimestamp;
+    struct
+    {
+        UCHAR SystemRunning : 1;
+        UCHAR ConnectedStandbyInProgress : 1;
+        UCHAR UserShutdownInProgress : 1;
+        UCHAR SystemShutdownInProgress : 1;
+        UCHAR SleepInProgress : 4;
+    } Flags;
+    UCHAR ConnectedStandbyScenarioInstanceId;
+    UCHAR ConnectedStandbyEntryReason;
+    UCHAR ConnectedStandbyExitReason;
+    USHORT SystemSleepTransitionCount;
+    LARGE_INTEGER LastReferenceTime;
+    ULONG LastReferenceTimeChecksum;
+    ULONG LastUpdateBootId;
+} RTL_BSD_DATA_POWER_TRANSITION, *PRTL_BSD_DATA_POWER_TRANSITION;
+
+typedef struct _RTL_BSD_DATA_ERROR_INFO
+{
+    ULONG BootId;
+    ULONG RepeatCount;
+    ULONG OtherErrorCount;
+    ULONG Code;
+    ULONG OtherErrorCount2;
+} RTL_BSD_DATA_ERROR_INFO, *PRTL_BSD_DATA_ERROR_INFO;
+
+typedef struct _RTL_BSD_POWER_BUTTON_PRESS_INFO
+{
+    LARGE_INTEGER LastPressTime;
+    ULONG CumulativePressCount;
+    USHORT LastPressBootId;
+    UCHAR LastPowerWatchdogStage;
+    struct
+    {
+        UCHAR WatchdogArmed : 1;
+        UCHAR ShutdownInProgress : 1;
+    } Flags;
+    LARGE_INTEGER LastReleaseTime;
+    ULONG CumulativeReleaseCount;
+    USHORT LastReleaseBootId;
+    USHORT ErrorCount;
+    UCHAR CurrentConnectedStandbyPhase;
+    ULONG TransitionLatestCheckpointId;
+    ULONG TransitionLatestCheckpointType;
+    ULONG TransitionLatestCheckpointSequenceNumber;
+} RTL_BSD_POWER_BUTTON_PRESS_INFO, *PRTL_BSD_POWER_BUTTON_PRESS_INFO;
+
+//
+// Main Structure for "bootstat.dat" RTL Data File
+//
+typedef struct _RTL_BSD_DATA
+{
+    ULONG Version;                                          // RtlBsdItemVersionNumber
+    ULONG ProductType;                                      // RtlBsdItemProductType
+    BOOLEAN AabEnabled;                                     // RtlBsdItemAabEnabled
+    UCHAR AabTimeout;                                       // RtlBsdItemAabTimeout
+    BOOLEAN LastBootSucceeded;                              // RtlBsdItemBootGood
+    BOOLEAN LastBootShutdown;                               // RtlBsdItemBootShutdown
+    BOOLEAN SleepInProgress;                                // RtlBsdSleepInProgress
+    RTL_BSD_DATA_POWER_TRANSITION PowerTransition;          // RtlBsdPowerTransition
+    UCHAR BootAttemptCount;                                 // RtlBsdItemBootAttemptCount
+    UCHAR LastBootCheckpoint;                               // RtlBsdItemBootCheckpoint
+    UCHAR Checksum;                                         // RtlBsdItemChecksum
+    ULONG LastBootId;                                       // RtlBsdItemBootId
+    ULONG LastSuccessfulShutdownBootId;                     // RtlBsdItemShutdownBootId
+    ULONG LastReportedAbnormalShutdownBootId;               // RtlBsdItemReportedAbnormalShutdownBootId
+    RTL_BSD_DATA_ERROR_INFO ErrorInfo;                      // RtlBsdItemErrorInfo
+    RTL_BSD_POWER_BUTTON_PRESS_INFO PowerButtonPressInfo;   // RtlBsdItemPowerButtonPressInfo
+} RTL_BSD_DATA, *PRTL_BSD_DATA;
+
 #ifdef NTOS_MODE_USER
 //
 // Exception Record
index 7279a2e..573e4c0 100644 (file)
@@ -56,6 +56,7 @@ list(APPEND SOURCE
     slist.c
     sid.c
     splaytree.c
+    sysvol.c
     thread.c
     time.c
     timezone.c
index 77d3674..b674eb2 100644 (file)
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS system libraries
- * PURPOSE:         Boot Data implementation
+ * PROJECT:         ReactOS Runtime Library
+ * LICENSE:         See COPYING in the top level directory
  * FILE:            lib/rtl/bootdata.c
- * PROGRAMMERS:
+ * PURPOSE:         Boot Status Data Implementation
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ *                  Eric Kohl
  */
 
 /* INCLUDES *****************************************************************/
 
 #include <rtl.h>
-
 #define NDEBUG
 #include <debug.h>
 
-typedef struct _RTL_BSD_ITEM
+typedef struct _RTL_BSD_ITEM_TABLE_ENTRY
 {
-    ULONG Offset;
-    ULONG Size;
-} RTL_BSD_ITEM, *PRTL_BSD_ITEM;
+    UCHAR Offset;
+    UCHAR Size;
+} RTL_BSD_ITEM_TABLE_ENTRY;
 
 /* FUNCTIONS *****************************************************************/
 
-static SID_IDENTIFIER_AUTHORITY LocalSystemAuthority = {SECURITY_NT_AUTHORITY};
-
-static RTL_BSD_ITEM BsdItemTable[6] = {{0, 4}, {4, 4,}, {8, 1}, {9, 1}, {10, 1}, {11, 1}};
-
-static NTSTATUS
-RtlpSysVolCreateSecurityDescriptor(OUT PISECURITY_DESCRIPTOR *SecurityDescriptor,
-                                   OUT PSID *SystemSid)
-{
-    PSECURITY_DESCRIPTOR AbsSD = NULL;
-    PSID LocalSystemSid = NULL;
-    PACL Dacl = NULL;
-    ULONG DaclSize;
-    NTSTATUS Status;
-
-    /* create the local SYSTEM SID */
-    Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
-                                         1,
-                                         SECURITY_LOCAL_SYSTEM_RID,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         &LocalSystemSid);
-    if (!NT_SUCCESS(Status))
-    {
-        return Status;
-    }
-
-    /* allocate and initialize the security descriptor */
-    AbsSD = RtlpAllocateMemory(sizeof(SECURITY_DESCRIPTOR),
-                               'dSeS');
-    if (AbsSD == NULL)
-    {
-        Status = STATUS_NO_MEMORY;
-        goto Cleanup;
-    }
-
-    Status = RtlCreateSecurityDescriptor(AbsSD,
-                                         SECURITY_DESCRIPTOR_REVISION);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Cleanup;
-    }
-
-    /* allocate and create the DACL */
-    DaclSize = sizeof(ACL) + sizeof(ACE) +
-               RtlLengthSid(LocalSystemSid);
-    Dacl = RtlpAllocateMemory(DaclSize,
-                              'cAeS');
-    if (Dacl == NULL)
-    {
-        Status = STATUS_NO_MEMORY;
-        goto Cleanup;
-    }
-
-    Status = RtlCreateAcl(Dacl,
-                          DaclSize,
-                          ACL_REVISION);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Cleanup;
-    }
-
-    Status = RtlAddAccessAllowedAceEx(Dacl,
-                                      ACL_REVISION,
-                                      OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
-                                      STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
-                                      LocalSystemSid);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Cleanup;
-    }
-
-    /* set the DACL in the security descriptor */
-    Status = RtlSetDaclSecurityDescriptor(AbsSD,
-                                          TRUE,
-                                          Dacl,
-                                          FALSE);
-
-    /* all done */
-    if (NT_SUCCESS(Status))
-    {
-        *SecurityDescriptor = AbsSD;
-        *SystemSid = LocalSystemSid;
-    }
-    else
-    {
-Cleanup:
-        if (LocalSystemSid != NULL)
-        {
-            RtlFreeSid(LocalSystemSid);
-        }
-
-        if (Dacl != NULL)
-        {
-            RtlpFreeMemory(Dacl,
-                           'cAeS');
-        }
-
-        if (AbsSD != NULL)
-        {
-            RtlpFreeMemory(AbsSD,
-                           'dSeS');
-        }
-    }
-
-    return Status;
-}
-
-static NTSTATUS
-RtlpSysVolCheckOwnerAndSecurity(IN HANDLE DirectoryHandle,
-                                IN PISECURITY_DESCRIPTOR SecurityDescriptor)
+PRTL_BSD_DATA DummyBsd;
+RTL_BSD_ITEM_TABLE_ENTRY BsdItemTable[RtlBsdItemMax] =
 {
-    PSECURITY_DESCRIPTOR RelSD = NULL;
-    PSECURITY_DESCRIPTOR NewRelSD = NULL;
-    PSECURITY_DESCRIPTOR AbsSD = NULL;
-#ifdef _WIN64
-    BOOLEAN AbsSDAllocated = FALSE;
-#endif
-    PSID AdminSid = NULL;
-    PSID LocalSystemSid = NULL;
-    ULONG DescriptorSize;
-    ULONG AbsSDSize, RelSDSize = 0;
-    PACL Dacl;
-    BOOLEAN DaclPresent, DaclDefaulted;
-    PSID OwnerSid;
-    BOOLEAN OwnerDefaulted;
-    ULONG AceIndex;
-    PACE Ace = NULL;
-    NTSTATUS Status;
-
-    /* find out how much memory we need to allocate for the self-relative
-       descriptor we're querying */
-    Status = ZwQuerySecurityObject(DirectoryHandle,
-                                   OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
-                                   NULL,
-                                   0,
-                                   &DescriptorSize);
-    if (Status != STATUS_BUFFER_TOO_SMALL)
-    {
-        /* looks like the FS doesn't support security... return success */
-        Status = STATUS_SUCCESS;
-        goto Cleanup;
-    }
-
-    /* allocate enough memory for the security descriptor */
-    RelSD = RtlpAllocateMemory(DescriptorSize,
-                               'dSeS');
-    if (RelSD == NULL)
-    {
-        Status = STATUS_NO_MEMORY;
-        goto Cleanup;
-    }
-
-    /* query the self-relative security descriptor */
-    Status = ZwQuerySecurityObject(DirectoryHandle,
-                                   OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
-                                   RelSD,
-                                   DescriptorSize,
-                                   &DescriptorSize);
-    if (!NT_SUCCESS(Status))
-    {
-        /* FIXME - handle the case where someone else modified the owner and/or
-                   DACL while we allocated memory. But that should be *very*
-                   unlikely.... */
-        goto Cleanup;
-    }
-
-    /* query the owner and DACL from the descriptor */
-    Status = RtlGetOwnerSecurityDescriptor(RelSD,
-                                           &OwnerSid,
-                                           &OwnerDefaulted);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Cleanup;
-    }
-
-    Status = RtlGetDaclSecurityDescriptor(RelSD,
-                                          &DaclPresent,
-                                          &Dacl,
-                                          &DaclDefaulted);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Cleanup;
-    }
-
-    /* create the Administrators SID */
-    Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
-                                         2,
-                                         SECURITY_BUILTIN_DOMAIN_RID,
-                                         DOMAIN_ALIAS_RID_ADMINS,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         &AdminSid);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Cleanup;
-    }
-
-    /* create the local SYSTEM SID */
-    Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
-                                         1,
-                                         SECURITY_LOCAL_SYSTEM_RID,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         &LocalSystemSid);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Cleanup;
-    }
-
-    /* check if the Administrators are the owner and at least a not-NULL DACL
-       is present */
-    if (OwnerSid != NULL &&
-        RtlEqualSid(OwnerSid,
-                    AdminSid) &&
-        DaclPresent && Dacl != NULL)
-    {
-        /* check the DACL for an Allowed ACE for the SYSTEM account */
-        AceIndex = 0;
-        do
-        {
-            Status = RtlGetAce(Dacl,
-                               AceIndex++,
-                               (PVOID*)&Ace);
-            if (!NT_SUCCESS(Status))
-            {
-                Ace = NULL;
-            }
-            else if (Ace != NULL && Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
-            {
-                /* check if the the ACE is a set of allowed permissions for the
-                   local SYSTEM account */
-                if (RtlEqualSid((PSID)(Ace + 1),
-                                LocalSystemSid))
-                {
-                    /* check if the ACE is inherited by noncontainer and
-                       container objects, if not attempt to change that */
-                    if (!(Ace->Header.AceFlags & OBJECT_INHERIT_ACE) ||
-                        !(Ace->Header.AceFlags & CONTAINER_INHERIT_ACE))
-                    {
-                        Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
-                        Status = ZwSetSecurityObject(DirectoryHandle,
-                                                     DACL_SECURITY_INFORMATION,
-                                                     RelSD);
-                    }
-                    else
-                    {
-                        /* all done, we have access */
-                        Status = STATUS_SUCCESS;
-                    }
-
-                    goto Cleanup;
-                }
-            }
-        } while (Ace != NULL);
-    }
-
-    AbsSDSize = DescriptorSize;
-
-    /* because we need to change any existing data we need to convert it to
-       an absolute security descriptor first */
-    Status = RtlSelfRelativeToAbsoluteSD2(RelSD,
-                                          &AbsSDSize);
-#ifdef _WIN64
-    if (Status == STATUS_BUFFER_TOO_SMALL)
-    {
-        /* this error code can only be returned on 64 bit builds because
-           the size of an absolute security descriptor is greater than the
-           size of a self-relative security descriptor */
-        ASSERT(AbsSDSize > DescriptorSize);
-
-        AbsSD = RtlpAllocateMemory(DescriptorSize,
-                                   'dSeS');
-        if (AbsSD == NULL)
-        {
-            Status = STATUS_NO_MEMORY;
-            goto Cleanup;
-        }
-
-        AbsSDAllocated = TRUE;
-
-        /* make a raw copy of the self-relative descriptor */
-        RtlCopyMemory(AbsSD,
-                      RelSD,
-                      DescriptorSize);
-
-        /* finally convert it */
-        Status = RtlSelfRelativeToAbsoluteSD2(AbsSD,
-                                              &AbsSDSize);
-    }
-    else
-#endif
-    {
-        AbsSD = RelSD;
-    }
-
-    if (!NT_SUCCESS(Status))
-    {
-        goto Cleanup;
-    }
-
-    /* set the owner SID */
-    Status = RtlSetOwnerSecurityDescriptor(AbsSD,
-                                           AdminSid,
-                                           FALSE);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Cleanup;
-    }
-
-    /* set the DACL in the security descriptor */
-    Status = RtlSetDaclSecurityDescriptor(AbsSD,
-                                          TRUE,
-                                          SecurityDescriptor->Dacl,
-                                          FALSE);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Cleanup;
-    }
-
-    /* convert it back to a self-relative descriptor, find out how much
-       memory we need */
-    Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
-                                         NULL,
-                                         &RelSDSize);
-    if (Status != STATUS_BUFFER_TOO_SMALL)
-    {
-        goto Cleanup;
-    }
-
-    /* allocate enough memory for the new self-relative descriptor */
-    NewRelSD = RtlpAllocateMemory(RelSDSize,
-                                  'dSeS');
-    if (NewRelSD == NULL)
-    {
-        Status = STATUS_NO_MEMORY;
-        goto Cleanup;
-    }
-
-    /* convert the security descriptor to self-relative format */
-    Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
-                                         NewRelSD,
-                                         &RelSDSize);
-    if (Status == STATUS_BUFFER_TOO_SMALL)
-    {
-        goto Cleanup;
-    }
-
-    /* finally attempt to change the security information */
-    Status = ZwSetSecurityObject(DirectoryHandle,
-                                 OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
-                                 NewRelSD);
-
-Cleanup:
-    if (AdminSid != NULL)
     {
-        RtlFreeSid(AdminSid);
-    }
-
-    if (LocalSystemSid != NULL)
+        FIELD_OFFSET(RTL_BSD_DATA, Version),
+        sizeof(&DummyBsd->Version)
+    },  // RtlBsdItemVersionNumber
     {
-        RtlFreeSid(LocalSystemSid);
-    }
-
-    if (RelSD != NULL)
+        FIELD_OFFSET(RTL_BSD_DATA, ProductType),
+        sizeof(&DummyBsd->ProductType)
+    },  // RtlBsdItemProductType
     {
-        RtlpFreeMemory(RelSD,
-                       'dSeS');
-    }
-
-    if (NewRelSD != NULL)
+        FIELD_OFFSET(RTL_BSD_DATA, AabEnabled),
+        sizeof(&DummyBsd->AabEnabled)
+    },  // RtlBsdItemAabEnabled
     {
-        RtlpFreeMemory(NewRelSD,
-                       'dSeS');
-    }
-
-#ifdef _WIN64
-    if (AbsSDAllocated)
+        FIELD_OFFSET(RTL_BSD_DATA, AabTimeout),
+        sizeof(&DummyBsd->AabTimeout)
+    },  // RtlBsdItemAabTimeout
     {
-        RtlpFreeMemory(AbsSD,
-                       'dSeS');
-    }
-#endif
-
-    return Status;
-}
-
-static NTSTATUS
-RtlpSysVolTakeOwnership(IN PUNICODE_STRING DirectoryPath,
-                        IN PSECURITY_DESCRIPTOR SecurityDescriptor)
-{
-    TOKEN_PRIVILEGES TokenPrivileges;
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    SECURITY_DESCRIPTOR AbsSD;
-    PSID AdminSid = NULL;
-    IO_STATUS_BLOCK IoStatusBlock;
-    BOOLEAN TokenEnabled = FALSE;
-    HANDLE hToken = NULL;
-    HANDLE hDirectory = NULL;
-    NTSTATUS Status;
-    ULONG ReturnLength;
-
-    Status = ZwOpenProcessToken(NtCurrentProcess(),
-                                TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
-                                &hToken);
-    if (!NT_SUCCESS(Status))
+        FIELD_OFFSET(RTL_BSD_DATA, LastBootSucceeded),
+        sizeof(&DummyBsd->LastBootSucceeded)
+    },  // RtlBsdItemBootGood
     {
-        goto Cleanup;
-    }
-
-    /* attempt to enable the SE_TAKE_OWNERSHIP_PRIVILEGE privilege */
-    TokenPrivileges.PrivilegeCount = 1;
-    TokenPrivileges.Privileges[0].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
-    TokenPrivileges.Privileges[0].Luid.HighPart = 0;
-    TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
-    Status = ZwAdjustPrivilegesToken(hToken,
-                                     FALSE,
-                                     &TokenPrivileges,
-                                     sizeof(TokenPrivileges),
-                                     &TokenPrivileges,
-                                     &ReturnLength);
-    if (!NT_SUCCESS(Status))
+        FIELD_OFFSET(RTL_BSD_DATA, LastBootShutdown),
+        sizeof(&DummyBsd->LastBootShutdown)
+    },  // RtlBsdItemBootShutdown
     {
-        goto Cleanup;
-    }
-    TokenEnabled = (TokenPrivileges.PrivilegeCount != 0);
-
-    /* open the directory */
-    InitializeObjectAttributes(&ObjectAttributes,
-                               DirectoryPath,
-                               0,
-                               NULL,
-                               SecurityDescriptor);
-
-    Status = ZwOpenFile(&hDirectory,
-                        SYNCHRONIZE | WRITE_OWNER,
-                        &ObjectAttributes,
-                        &IoStatusBlock,
-                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
-    if (!NT_SUCCESS(Status))
+        FIELD_OFFSET(RTL_BSD_DATA, SleepInProgress),
+        sizeof(&DummyBsd->SleepInProgress)
+    },  // RtlBsdSleepInProgress
     {
-        goto Cleanup;
-    }
-
-    /* create the Administrators SID */
-    Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
-                                         2,
-                                         SECURITY_BUILTIN_DOMAIN_RID,
-                                         DOMAIN_ALIAS_RID_ADMINS,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         0,
-                                         &AdminSid);
-    if (!NT_SUCCESS(Status))
+        FIELD_OFFSET(RTL_BSD_DATA, PowerTransition),
+        sizeof(&DummyBsd->PowerTransition)
+    },  // RtlBsdPowerTransition
     {
-        goto Cleanup;
-    }
-
-    /* create the security descriptor */
-    Status = RtlCreateSecurityDescriptor(&AbsSD,
-                                         SECURITY_DESCRIPTOR_REVISION);
-    if (!NT_SUCCESS(Status))
+        FIELD_OFFSET(RTL_BSD_DATA, BootAttemptCount),
+        sizeof(&DummyBsd->BootAttemptCount)
+    },  // RtlBsdItemBootAttemptCount
     {
-        goto Cleanup;
-    }
-
-    Status = RtlSetOwnerSecurityDescriptor(&AbsSD,
-                                           AdminSid,
-                                           FALSE);
-    if (!NT_SUCCESS(Status))
+        FIELD_OFFSET(RTL_BSD_DATA, LastBootCheckpoint),
+        sizeof(&DummyBsd->LastBootCheckpoint)
+    },  // RtlBsdItemBootCheckpoint
     {
-        goto Cleanup;
-    }
-
-    /* attempt to take ownership */
-    Status = ZwSetSecurityObject(hDirectory,
-                                 OWNER_SECURITY_INFORMATION,
-                                 &AbsSD);
-
-Cleanup:
-    if (TokenEnabled)
+        FIELD_OFFSET(RTL_BSD_DATA, LastBootId),
+        sizeof(&DummyBsd->LastBootId)
+    },  // RtlBsdItemBootId
     {
-        ZwAdjustPrivilegesToken(hToken,
-                                FALSE,
-                                &TokenPrivileges,
-                                0,
-                                NULL,
-                                NULL);
-    }
-
-    if (AdminSid != NULL)
+        FIELD_OFFSET(RTL_BSD_DATA, LastSuccessfulShutdownBootId),
+        sizeof(&DummyBsd->LastSuccessfulShutdownBootId)
+    },  // RtlBsdItemShutdownBootId
     {
-        RtlFreeSid(AdminSid);
-    }
-
-    if (hDirectory != NULL)
+        FIELD_OFFSET(RTL_BSD_DATA, LastReportedAbnormalShutdownBootId),
+        sizeof(&DummyBsd->LastReportedAbnormalShutdownBootId)
+    },  // RtlBsdItemReportedAbnormalShutdownBootId
     {
-        ZwClose(hDirectory);
-    }
-
-    if (hToken != NULL)
+        FIELD_OFFSET(RTL_BSD_DATA, ErrorInfo),
+        sizeof(&DummyBsd->ErrorInfo)
+    },  // RtlBsdItemErrorInfo
     {
-        ZwClose(hToken);
-    }
-
-    return Status;
-}
-
-/*
-* @implemented
-*/
-NTSTATUS
-NTAPI
-RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath)
-{
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    IO_STATUS_BLOCK IoStatusBlock;
-    HANDLE hDirectory;
-    UNICODE_STRING DirectoryName, NewPath;
-    ULONG PathLen;
-    PISECURITY_DESCRIPTOR SecurityDescriptor = NULL;
-    PSID SystemSid = NULL;
-    BOOLEAN AddSep = FALSE;
-    NTSTATUS Status;
-
-    PAGED_CODE_RTL();
-
-    RtlInitUnicodeString(&DirectoryName,
-                         L"System Volume Information");
-
-    PathLen = VolumeRootPath->Length + DirectoryName.Length;
-
-    /* make sure we don't overflow while appending the strings */
-    if (PathLen > 0xFFFC)
-    {
-        return STATUS_INVALID_PARAMETER;
-    }
-
-    if (VolumeRootPath->Buffer[(VolumeRootPath->Length / sizeof(WCHAR)) - 1] != L'\\')
-    {
-        AddSep = TRUE;
-        PathLen += sizeof(WCHAR);
-    }
-
-    /* allocate the new string */
-    NewPath.MaximumLength = (USHORT)PathLen + sizeof(WCHAR);
-    NewPath.Buffer = RtlpAllocateStringMemory(NewPath.MaximumLength,
-                                              TAG_USTR);
-    if (NewPath.Buffer == NULL)
-    {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    /* create the new path string */
-    NewPath.Length = VolumeRootPath->Length;
-    RtlCopyMemory(NewPath.Buffer,
-                  VolumeRootPath->Buffer,
-                  NewPath.Length);
-    if (AddSep)
-    {
-        NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\\';
-        NewPath.Length += sizeof(WCHAR);
-    }
-    RtlCopyMemory(NewPath.Buffer + (NewPath.Length / sizeof(WCHAR)),
-                  DirectoryName.Buffer,
-                  DirectoryName.Length);
-    NewPath.Length += DirectoryName.Length;
-    NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\0';
-
-    ASSERT(NewPath.Length == PathLen);
-    ASSERT(NewPath.Length == NewPath.MaximumLength - sizeof(WCHAR));
-
-    /* create the security descriptor for the new directory */
-    Status = RtlpSysVolCreateSecurityDescriptor(&SecurityDescriptor,
-                                                &SystemSid);
-    if (NT_SUCCESS(Status))
+        FIELD_OFFSET(RTL_BSD_DATA, PowerButtonPressInfo),
+        sizeof(&DummyBsd->PowerButtonPressInfo)
+    },  // RtlBsdItemPowerButtonPressInfo
     {
-        /* create or open the directory */
-        InitializeObjectAttributes(&ObjectAttributes,
-                                   &NewPath,
-                                   0,
-                                   NULL,
-                                   SecurityDescriptor);
-
-        Status = ZwCreateFile(&hDirectory,
-                              SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
-                              &ObjectAttributes,
-                              &IoStatusBlock,
-                              NULL,
-                              FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
-                              FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                              FILE_OPEN_IF,
-                              FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
-                              NULL,
-                              0);
-        if (!NT_SUCCESS(Status))
-        {
-            Status = RtlpSysVolTakeOwnership(&NewPath,
-                                             SecurityDescriptor);
-
-            if (NT_SUCCESS(Status))
-            {
-                /* successfully took ownership, attempt to open it */
-                Status = ZwCreateFile(&hDirectory,
-                                      SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
-                                      &ObjectAttributes,
-                                      &IoStatusBlock,
-                                      NULL,
-                                      FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
-                                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                                      FILE_OPEN_IF,
-                                      FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
-                                      NULL,
-                                      0);
-            }
-        }
-
-        if (NT_SUCCESS(Status))
-        {
-            /* check security now and adjust it if neccessary */
-            Status = RtlpSysVolCheckOwnerAndSecurity(hDirectory,
-                                                     SecurityDescriptor);
-            ZwClose(hDirectory);
-        }
-
-        /* free allocated memory */
-        ASSERT(SecurityDescriptor != NULL);
-        ASSERT(SecurityDescriptor->Dacl != NULL);
-
-        RtlpFreeMemory(SecurityDescriptor->Dacl,
-                       'cAeS');
-        RtlpFreeMemory(SecurityDescriptor,
-                       'dSeS');
-
-        RtlFreeSid(SystemSid);
-    }
-
-    RtlpFreeStringMemory(NewPath.Buffer,
-                         TAG_USTR);
-    return Status;
-}
+        FIELD_OFFSET(RTL_BSD_DATA, Checksum),
+        sizeof(&DummyBsd->Checksum)
+    },  // RtlBsdItemChecksum
+};
 
 /*
-* @implemented
-*/
+ * @implemented
+ */
 NTSTATUS
 NTAPI
-RtlCreateBootStatusDataFile(VOID)
+RtlCreateBootStatusDataFile (
+    VOID
+    )
 {
-    OBJECT_ATTRIBUTES ObjectAttributes;
     IO_STATUS_BLOCK IoStatusBlock;
     LARGE_INTEGER AllocationSize;
     LARGE_INTEGER ByteOffset;
-    UNICODE_STRING FileName;
+    UNICODE_STRING FileName =
+        RTL_CONSTANT_STRING(L"\\SystemRoot\\bootstat.dat");
+    OBJECT_ATTRIBUTES ObjectAttributes =
+        RTL_CONSTANT_OBJECT_ATTRIBUTES(&FileName, OBJ_CASE_INSENSITIVE);
     HANDLE FileHandle;
     NTSTATUS Status;
+    RTL_BSD_DATA InitialBsd;
 
-    /* Initialize the file name */
-    RtlInitUnicodeString(&FileName,
-                         L"\\SystemRoot\\bootstat.dat");
-
-    /* Initialize the object attributes */
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &FileName,
-                               OBJ_CASE_INSENSITIVE,
-                               NULL,
-                               NULL);
-
+    /* Create the boot status data file */
     AllocationSize.QuadPart = 0x800;
     DBG_UNREFERENCED_LOCAL_VARIABLE(AllocationSize);
-
-    /* Create the boot status data file */
     Status = ZwCreateFile(&FileHandle,
                           FILE_GENERIC_READ | FILE_GENERIC_WRITE,
                           &ObjectAttributes,
@@ -723,17 +126,23 @@ RtlCreateBootStatusDataFile(VOID)
                           0);
     if (NT_SUCCESS(Status))
     {
-        // FIXME: Initialize the buffer in a better way.
-        UCHAR Buffer[12] = {0xC,0,0,0, 1,0,0,0, 1, 0x1e, 1, 0};
+        /* Setup a sane looking initial BSD */
+        RtlZeroMemory(&InitialBsd, sizeof(InitialBsd));
+        InitialBsd.Version = sizeof(InitialBsd);
+        InitialBsd.ProductType = NtProductWinNt;
+        InitialBsd.AabEnabled = 1;
+        InitialBsd.AabTimeout = 30;
+        InitialBsd.LastBootSucceeded = TRUE;
 
+        /* Write it to disk */
         ByteOffset.QuadPart = 0;
         Status = ZwWriteFile(FileHandle,
                              NULL,
                              NULL,
                              NULL,
                              &IoStatusBlock,
-                             &Buffer,
-                             12, //BufferSize,
+                             &InitialBsd,
+                             sizeof(InitialBsd),
                              &ByteOffset,
                              NULL);
     }
@@ -745,34 +154,40 @@ RtlCreateBootStatusDataFile(VOID)
 }
 
 /*
-* @implemented
-*/
+ * @implemented
+ */
 NTSTATUS
 NTAPI
-RtlGetSetBootStatusData(IN HANDLE FileHandle,
-                        IN BOOLEAN WriteMode,
-                        IN RTL_BSD_ITEM_TYPE DataClass,
-                        IN PVOID Buffer,
-                        IN ULONG BufferSize,
-                        OUT PULONG ReturnLength)
+RtlGetSetBootStatusData (
+    _In_ HANDLE FileHandle,
+    _In_ BOOLEAN Read,
+    _In_ RTL_BSD_ITEM_TYPE DataClass,
+    _In_ PVOID Buffer,
+    _In_ ULONG BufferSize,
+    _Out_opt_ PULONG ReturnLength
+    )
 {
     IO_STATUS_BLOCK IoStatusBlock;
     LARGE_INTEGER ByteOffset;
     NTSTATUS Status;
 
     DPRINT("RtlGetSetBootStatusData (%p %u %d %p %lu %p)\n",
-           FileHandle, WriteMode, DataClass, Buffer, BufferSize, ReturnLength);
+           FileHandle, Read, DataClass, Buffer, BufferSize, ReturnLength);
 
     if (DataClass >= RtlBsdItemMax)
+    {
         return STATUS_INVALID_PARAMETER;
+    }
 
     if (BufferSize > BsdItemTable[DataClass].Size)
+    {
         return STATUS_BUFFER_TOO_SMALL;
+    }
 
     ByteOffset.HighPart = 0;
     ByteOffset.LowPart = BsdItemTable[DataClass].Offset;
 
-    if (WriteMode)
+    if (Read)
     {
         Status = ZwReadFile(FileHandle,
                             NULL,
@@ -800,39 +215,34 @@ RtlGetSetBootStatusData(IN HANDLE FileHandle,
     if (NT_SUCCESS(Status))
     {
         if (ReturnLength)
+        {
             *ReturnLength = BsdItemTable[DataClass].Size;
+        }
     }
 
     return Status;
 }
 
 /*
-* @implemented
-*/
+ * @implemented
+ */
 NTSTATUS
 NTAPI
-RtlLockBootStatusData(OUT PHANDLE FileHandle)
+RtlLockBootStatusData (
+    _Out_ PHANDLE FileHandle
+    )
 {
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    IO_STATUS_BLOCK IoStatusBlock;
-    UNICODE_STRING FileName;
+    UNICODE_STRING FileName =
+        RTL_CONSTANT_STRING(L"\\SystemRoot\\bootstat.dat");
+    OBJECT_ATTRIBUTES ObjectAttributes =
+        RTL_CONSTANT_OBJECT_ATTRIBUTES(&FileName, OBJ_CASE_INSENSITIVE);
     HANDLE LocalFileHandle;
     NTSTATUS Status;
+    IO_STATUS_BLOCK IoStatusBlock;
 
     /* Intialize the file handle */
     *FileHandle = NULL;
 
-    /* Initialize the file name */
-    RtlInitUnicodeString(&FileName,
-                         L"\\SystemRoot\\bootstat.dat");
-
-    /* Initialize the object attributes */
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &FileName,
-                               0,
-                               NULL,
-                               NULL);
-
     /* Open the boot status data file */
     Status = ZwOpenFile(&LocalFileHandle,
                         FILE_ALL_ACCESS,
@@ -850,18 +260,18 @@ RtlLockBootStatusData(OUT PHANDLE FileHandle)
 }
 
 /*
-* @implemented
-*/
+ * @implemented
+ */
 NTSTATUS
 NTAPI
-RtlUnlockBootStatusData(IN HANDLE FileHandle)
+RtlUnlockBootStatusData (
+    _In_ HANDLE FileHandle
+    )
 {
     IO_STATUS_BLOCK IoStatusBlock;
 
     /* Flush the file and close it */
-    ZwFlushBuffersFile(FileHandle,
-                       &IoStatusBlock);
-
+    ZwFlushBuffersFile(FileHandle, &IoStatusBlock);
     return ZwClose(FileHandle);
 }
 
diff --git a/sdk/lib/rtl/sysvol.c b/sdk/lib/rtl/sysvol.c
new file mode 100644 (file)
index 0000000..67c79df
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS system libraries
+ * PURPOSE:         Boot Data implementation
+ * FILE:            lib/rtl/bootdata.c
+ * PROGRAMMERS:
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include <rtl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+static SID_IDENTIFIER_AUTHORITY LocalSystemAuthority = {SECURITY_NT_AUTHORITY};
+
+static NTSTATUS
+RtlpSysVolCreateSecurityDescriptor(OUT PISECURITY_DESCRIPTOR *SecurityDescriptor,
+                                   OUT PSID *SystemSid)
+{
+    PSECURITY_DESCRIPTOR AbsSD = NULL;
+    PSID LocalSystemSid = NULL;
+    PACL Dacl = NULL;
+    ULONG DaclSize;
+    NTSTATUS Status;
+
+    /* create the local SYSTEM SID */
+    Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
+                                         1,
+                                         SECURITY_LOCAL_SYSTEM_RID,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         &LocalSystemSid);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* allocate and initialize the security descriptor */
+    AbsSD = RtlpAllocateMemory(sizeof(SECURITY_DESCRIPTOR),
+                               'dSeS');
+    if (AbsSD == NULL)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Cleanup;
+    }
+
+    Status = RtlCreateSecurityDescriptor(AbsSD,
+                                         SECURITY_DESCRIPTOR_REVISION);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* allocate and create the DACL */
+    DaclSize = sizeof(ACL) + sizeof(ACE) +
+               RtlLengthSid(LocalSystemSid);
+    Dacl = RtlpAllocateMemory(DaclSize,
+                              'cAeS');
+    if (Dacl == NULL)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Cleanup;
+    }
+
+    Status = RtlCreateAcl(Dacl,
+                          DaclSize,
+                          ACL_REVISION);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    Status = RtlAddAccessAllowedAceEx(Dacl,
+                                      ACL_REVISION,
+                                      OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
+                                      STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
+                                      LocalSystemSid);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* set the DACL in the security descriptor */
+    Status = RtlSetDaclSecurityDescriptor(AbsSD,
+                                          TRUE,
+                                          Dacl,
+                                          FALSE);
+
+    /* all done */
+    if (NT_SUCCESS(Status))
+    {
+        *SecurityDescriptor = AbsSD;
+        *SystemSid = LocalSystemSid;
+    }
+    else
+    {
+Cleanup:
+        if (LocalSystemSid != NULL)
+        {
+            RtlFreeSid(LocalSystemSid);
+        }
+
+        if (Dacl != NULL)
+        {
+            RtlpFreeMemory(Dacl,
+                           'cAeS');
+        }
+
+        if (AbsSD != NULL)
+        {
+            RtlpFreeMemory(AbsSD,
+                           'dSeS');
+        }
+    }
+
+    return Status;
+}
+
+static NTSTATUS
+RtlpSysVolCheckOwnerAndSecurity(IN HANDLE DirectoryHandle,
+                                IN PISECURITY_DESCRIPTOR SecurityDescriptor)
+{
+    PSECURITY_DESCRIPTOR RelSD = NULL;
+    PSECURITY_DESCRIPTOR NewRelSD = NULL;
+    PSECURITY_DESCRIPTOR AbsSD = NULL;
+#ifdef _WIN64
+    BOOLEAN AbsSDAllocated = FALSE;
+#endif
+    PSID AdminSid = NULL;
+    PSID LocalSystemSid = NULL;
+    ULONG DescriptorSize;
+    ULONG AbsSDSize, RelSDSize = 0;
+    PACL Dacl;
+    BOOLEAN DaclPresent, DaclDefaulted;
+    PSID OwnerSid;
+    BOOLEAN OwnerDefaulted;
+    ULONG AceIndex;
+    PACE Ace = NULL;
+    NTSTATUS Status;
+
+    /* find out how much memory we need to allocate for the self-relative
+       descriptor we're querying */
+    Status = ZwQuerySecurityObject(DirectoryHandle,
+                                   OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
+                                   NULL,
+                                   0,
+                                   &DescriptorSize);
+    if (Status != STATUS_BUFFER_TOO_SMALL)
+    {
+        /* looks like the FS doesn't support security... return success */
+        Status = STATUS_SUCCESS;
+        goto Cleanup;
+    }
+
+    /* allocate enough memory for the security descriptor */
+    RelSD = RtlpAllocateMemory(DescriptorSize,
+                               'dSeS');
+    if (RelSD == NULL)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Cleanup;
+    }
+
+    /* query the self-relative security descriptor */
+    Status = ZwQuerySecurityObject(DirectoryHandle,
+                                   OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
+                                   RelSD,
+                                   DescriptorSize,
+                                   &DescriptorSize);
+    if (!NT_SUCCESS(Status))
+    {
+        /* FIXME - handle the case where someone else modified the owner and/or
+                   DACL while we allocated memory. But that should be *very*
+                   unlikely.... */
+        goto Cleanup;
+    }
+
+    /* query the owner and DACL from the descriptor */
+    Status = RtlGetOwnerSecurityDescriptor(RelSD,
+                                           &OwnerSid,
+                                           &OwnerDefaulted);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    Status = RtlGetDaclSecurityDescriptor(RelSD,
+                                          &DaclPresent,
+                                          &Dacl,
+                                          &DaclDefaulted);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* create the Administrators SID */
+    Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
+                                         2,
+                                         SECURITY_BUILTIN_DOMAIN_RID,
+                                         DOMAIN_ALIAS_RID_ADMINS,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         &AdminSid);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* create the local SYSTEM SID */
+    Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
+                                         1,
+                                         SECURITY_LOCAL_SYSTEM_RID,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         &LocalSystemSid);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* check if the Administrators are the owner and at least a not-NULL DACL
+       is present */
+    if (OwnerSid != NULL &&
+        RtlEqualSid(OwnerSid,
+                    AdminSid) &&
+        DaclPresent && Dacl != NULL)
+    {
+        /* check the DACL for an Allowed ACE for the SYSTEM account */
+        AceIndex = 0;
+        do
+        {
+            Status = RtlGetAce(Dacl,
+                               AceIndex++,
+                               (PVOID*)&Ace);
+            if (!NT_SUCCESS(Status))
+            {
+                Ace = NULL;
+            }
+            else if (Ace != NULL && Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
+            {
+                /* check if the the ACE is a set of allowed permissions for the
+                   local SYSTEM account */
+                if (RtlEqualSid((PSID)(Ace + 1),
+                                LocalSystemSid))
+                {
+                    /* check if the ACE is inherited by noncontainer and
+                       container objects, if not attempt to change that */
+                    if (!(Ace->Header.AceFlags & OBJECT_INHERIT_ACE) ||
+                        !(Ace->Header.AceFlags & CONTAINER_INHERIT_ACE))
+                    {
+                        Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
+                        Status = ZwSetSecurityObject(DirectoryHandle,
+                                                     DACL_SECURITY_INFORMATION,
+                                                     RelSD);
+                    }
+                    else
+                    {
+                        /* all done, we have access */
+                        Status = STATUS_SUCCESS;
+                    }
+
+                    goto Cleanup;
+                }
+            }
+        } while (Ace != NULL);
+    }
+
+    AbsSDSize = DescriptorSize;
+
+    /* because we need to change any existing data we need to convert it to
+       an absolute security descriptor first */
+    Status = RtlSelfRelativeToAbsoluteSD2(RelSD,
+                                          &AbsSDSize);
+#ifdef _WIN64
+    if (Status == STATUS_BUFFER_TOO_SMALL)
+    {
+        /* this error code can only be returned on 64 bit builds because
+           the size of an absolute security descriptor is greater than the
+           size of a self-relative security descriptor */
+        ASSERT(AbsSDSize > DescriptorSize);
+
+        AbsSD = RtlpAllocateMemory(DescriptorSize,
+                                   'dSeS');
+        if (AbsSD == NULL)
+        {
+            Status = STATUS_NO_MEMORY;
+            goto Cleanup;
+        }
+
+        AbsSDAllocated = TRUE;
+
+        /* make a raw copy of the self-relative descriptor */
+        RtlCopyMemory(AbsSD,
+                      RelSD,
+                      DescriptorSize);
+
+        /* finally convert it */
+        Status = RtlSelfRelativeToAbsoluteSD2(AbsSD,
+                                              &AbsSDSize);
+    }
+    else
+#endif
+    {
+        AbsSD = RelSD;
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* set the owner SID */
+    Status = RtlSetOwnerSecurityDescriptor(AbsSD,
+                                           AdminSid,
+                                           FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* set the DACL in the security descriptor */
+    Status = RtlSetDaclSecurityDescriptor(AbsSD,
+                                          TRUE,
+                                          SecurityDescriptor->Dacl,
+                                          FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* convert it back to a self-relative descriptor, find out how much
+       memory we need */
+    Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
+                                         NULL,
+                                         &RelSDSize);
+    if (Status != STATUS_BUFFER_TOO_SMALL)
+    {
+        goto Cleanup;
+    }
+
+    /* allocate enough memory for the new self-relative descriptor */
+    NewRelSD = RtlpAllocateMemory(RelSDSize,
+                                  'dSeS');
+    if (NewRelSD == NULL)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Cleanup;
+    }
+
+    /* convert the security descriptor to self-relative format */
+    Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
+                                         NewRelSD,
+                                         &RelSDSize);
+    if (Status == STATUS_BUFFER_TOO_SMALL)
+    {
+        goto Cleanup;
+    }
+
+    /* finally attempt to change the security information */
+    Status = ZwSetSecurityObject(DirectoryHandle,
+                                 OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
+                                 NewRelSD);
+
+Cleanup:
+    if (AdminSid != NULL)
+    {
+        RtlFreeSid(AdminSid);
+    }
+
+    if (LocalSystemSid != NULL)
+    {
+        RtlFreeSid(LocalSystemSid);
+    }
+
+    if (RelSD != NULL)
+    {
+        RtlpFreeMemory(RelSD,
+                       'dSeS');
+    }
+
+    if (NewRelSD != NULL)
+    {
+        RtlpFreeMemory(NewRelSD,
+                       'dSeS');
+    }
+
+#ifdef _WIN64
+    if (AbsSDAllocated)
+    {
+        RtlpFreeMemory(AbsSD,
+                       'dSeS');
+    }
+#endif
+
+    return Status;
+}
+
+static NTSTATUS
+RtlpSysVolTakeOwnership(IN PUNICODE_STRING DirectoryPath,
+                        IN PSECURITY_DESCRIPTOR SecurityDescriptor)
+{
+    TOKEN_PRIVILEGES TokenPrivileges;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    SECURITY_DESCRIPTOR AbsSD;
+    PSID AdminSid = NULL;
+    IO_STATUS_BLOCK IoStatusBlock;
+    BOOLEAN TokenEnabled = FALSE;
+    HANDLE hToken = NULL;
+    HANDLE hDirectory = NULL;
+    NTSTATUS Status;
+    ULONG ReturnLength;
+
+    Status = ZwOpenProcessToken(NtCurrentProcess(),
+                                TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
+                                &hToken);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* attempt to enable the SE_TAKE_OWNERSHIP_PRIVILEGE privilege */
+    TokenPrivileges.PrivilegeCount = 1;
+    TokenPrivileges.Privileges[0].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
+    TokenPrivileges.Privileges[0].Luid.HighPart = 0;
+    TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+    Status = ZwAdjustPrivilegesToken(hToken,
+                                     FALSE,
+                                     &TokenPrivileges,
+                                     sizeof(TokenPrivileges),
+                                     &TokenPrivileges,
+                                     &ReturnLength);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+    TokenEnabled = (TokenPrivileges.PrivilegeCount != 0);
+
+    /* open the directory */
+    InitializeObjectAttributes(&ObjectAttributes,
+                               DirectoryPath,
+                               0,
+                               NULL,
+                               SecurityDescriptor);
+
+    Status = ZwOpenFile(&hDirectory,
+                        SYNCHRONIZE | WRITE_OWNER,
+                        &ObjectAttributes,
+                        &IoStatusBlock,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* create the Administrators SID */
+    Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
+                                         2,
+                                         SECURITY_BUILTIN_DOMAIN_RID,
+                                         DOMAIN_ALIAS_RID_ADMINS,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         0,
+                                         &AdminSid);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* create the security descriptor */
+    Status = RtlCreateSecurityDescriptor(&AbsSD,
+                                         SECURITY_DESCRIPTOR_REVISION);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    Status = RtlSetOwnerSecurityDescriptor(&AbsSD,
+                                           AdminSid,
+                                           FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* attempt to take ownership */
+    Status = ZwSetSecurityObject(hDirectory,
+                                 OWNER_SECURITY_INFORMATION,
+                                 &AbsSD);
+
+Cleanup:
+    if (TokenEnabled)
+    {
+        ZwAdjustPrivilegesToken(hToken,
+                                FALSE,
+                                &TokenPrivileges,
+                                0,
+                                NULL,
+                                NULL);
+    }
+
+    if (AdminSid != NULL)
+    {
+        RtlFreeSid(AdminSid);
+    }
+
+    if (hDirectory != NULL)
+    {
+        ZwClose(hDirectory);
+    }
+
+    if (hToken != NULL)
+    {
+        ZwClose(hToken);
+    }
+
+    return Status;
+}
+
+/*
+* @implemented
+*/
+NTSTATUS
+NTAPI
+RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath)
+{
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    IO_STATUS_BLOCK IoStatusBlock;
+    HANDLE hDirectory;
+    UNICODE_STRING DirectoryName, NewPath;
+    ULONG PathLen;
+    PISECURITY_DESCRIPTOR SecurityDescriptor = NULL;
+    PSID SystemSid = NULL;
+    BOOLEAN AddSep = FALSE;
+    NTSTATUS Status;
+
+    PAGED_CODE_RTL();
+
+    RtlInitUnicodeString(&DirectoryName,
+                         L"System Volume Information");
+
+    PathLen = VolumeRootPath->Length + DirectoryName.Length;
+
+    /* make sure we don't overflow while appending the strings */
+    if (PathLen > 0xFFFC)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (VolumeRootPath->Buffer[(VolumeRootPath->Length / sizeof(WCHAR)) - 1] != L'\\')
+    {
+        AddSep = TRUE;
+        PathLen += sizeof(WCHAR);
+    }
+
+    /* allocate the new string */
+    NewPath.MaximumLength = (USHORT)PathLen + sizeof(WCHAR);
+    NewPath.Buffer = RtlpAllocateStringMemory(NewPath.MaximumLength,
+                                              TAG_USTR);
+    if (NewPath.Buffer == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* create the new path string */
+    NewPath.Length = VolumeRootPath->Length;
+    RtlCopyMemory(NewPath.Buffer,
+                  VolumeRootPath->Buffer,
+                  NewPath.Length);
+    if (AddSep)
+    {
+        NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\\';
+        NewPath.Length += sizeof(WCHAR);
+    }
+    RtlCopyMemory(NewPath.Buffer + (NewPath.Length / sizeof(WCHAR)),
+                  DirectoryName.Buffer,
+                  DirectoryName.Length);
+    NewPath.Length += DirectoryName.Length;
+    NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\0';
+
+    ASSERT(NewPath.Length == PathLen);
+    ASSERT(NewPath.Length == NewPath.MaximumLength - sizeof(WCHAR));
+
+    /* create the security descriptor for the new directory */
+    Status = RtlpSysVolCreateSecurityDescriptor(&SecurityDescriptor,
+                                                &SystemSid);
+    if (NT_SUCCESS(Status))
+    {
+        /* create or open the directory */
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &NewPath,
+                                   0,
+                                   NULL,
+                                   SecurityDescriptor);
+
+        Status = ZwCreateFile(&hDirectory,
+                              SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
+                              &ObjectAttributes,
+                              &IoStatusBlock,
+                              NULL,
+                              FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
+                              FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                              FILE_OPEN_IF,
+                              FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+                              NULL,
+                              0);
+        if (!NT_SUCCESS(Status))
+        {
+            Status = RtlpSysVolTakeOwnership(&NewPath,
+                                             SecurityDescriptor);
+
+            if (NT_SUCCESS(Status))
+            {
+                /* successfully took ownership, attempt to open it */
+                Status = ZwCreateFile(&hDirectory,
+                                      SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
+                                      &ObjectAttributes,
+                                      &IoStatusBlock,
+                                      NULL,
+                                      FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
+                                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                                      FILE_OPEN_IF,
+                                      FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+                                      NULL,
+                                      0);
+            }
+        }
+
+        if (NT_SUCCESS(Status))
+        {
+            /* check security now and adjust it if neccessary */
+            Status = RtlpSysVolCheckOwnerAndSecurity(hDirectory,
+                                                     SecurityDescriptor);
+            ZwClose(hDirectory);
+        }
+
+        /* free allocated memory */
+        ASSERT(SecurityDescriptor != NULL);
+        ASSERT(SecurityDescriptor->Dacl != NULL);
+
+        RtlpFreeMemory(SecurityDescriptor->Dacl,
+                       'cAeS');
+        RtlpFreeMemory(SecurityDescriptor,
+                       'dSeS');
+
+        RtlFreeSid(SystemSid);
+    }
+
+    RtlpFreeStringMemory(NewPath.Buffer,
+                         TAG_USTR);
+    return Status;
+}
+
+/* EOF */