mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-03 04:13:31 +00:00
- Cancel pending hive scynchronization upon shutdown.
- Implemented NtSetInformationKey(). - Mark more modified blocks in NtCreateKey(). svn path=/trunk/; revision=6306
This commit is contained in:
@@ -4,9 +4,7 @@
|
||||
* Configuration Manager structures and typedefs
|
||||
*/
|
||||
|
||||
/*
|
||||
* key query information class
|
||||
*/
|
||||
/* key query information class */
|
||||
|
||||
typedef enum _KEY_INFORMATION_CLASS
|
||||
{
|
||||
@@ -48,10 +46,19 @@ typedef struct _KEY_NODE_INFORMATION
|
||||
WCHAR Name[1];
|
||||
} KEY_NODE_INFORMATION, *PKEY_NODE_INFORMATION;
|
||||
|
||||
|
||||
/* key set information class */
|
||||
/*
|
||||
* KeyWriteTimeInformation
|
||||
*/
|
||||
|
||||
typedef enum _KEY_SET_INFORMATION_CLASS
|
||||
{
|
||||
KeyLastWriteTimeInformation
|
||||
} KEY_SET_INFORMATION_CLASS;
|
||||
|
||||
typedef struct _KEY_LAST_WRITE_TIME_INFORMATION
|
||||
{
|
||||
LARGE_INTEGER LastWriteTime;
|
||||
} KEY_LAST_WRITE_TIME_INFORMATION, *PKEY_LAST_WRITE_TIME_INFORMATION;
|
||||
|
||||
|
||||
/* key value information class */
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
/* $Id: zw.h,v 1.18 2003/10/04 17:10:55 ekohl Exp $
|
||||
/* $Id: zw.h,v 1.19 2003/10/13 20:52:31 ekohl Exp $
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
@@ -4724,11 +4724,11 @@ NtRaiseHardError(
|
||||
* ARGUMENTS:
|
||||
* KeyHandle = Handle to the registry key
|
||||
* KeyInformationClass = Index to the a certain information structure.
|
||||
Can be one of the following values:
|
||||
|
||||
* KeyWriteTimeInformation KEY_WRITE_TIME_INFORMATION
|
||||
|
||||
KeyInformation = Storage for the new information
|
||||
* Can be one of the following values:
|
||||
*
|
||||
* KeyLastWriteTimeInformation KEY_LAST_WRITE_TIME_INFORMATION
|
||||
*
|
||||
* KeyInformation = Storage for the new information
|
||||
* KeyInformationLength = Size of the information strucure
|
||||
* RETURNS: Status
|
||||
*/
|
||||
@@ -4737,7 +4737,7 @@ NTSTATUS
|
||||
STDCALL
|
||||
NtSetInformationKey(
|
||||
IN HANDLE KeyHandle,
|
||||
IN CINT KeyInformationClass,
|
||||
IN KEY_SET_INFORMATION_CLASS KeyInformationClass,
|
||||
IN PVOID KeyInformation,
|
||||
IN ULONG KeyInformationLength
|
||||
);
|
||||
@@ -5446,7 +5446,7 @@ ZwRaiseHardError(
|
||||
* KeyInformationClass = Index to the a certain information structure.
|
||||
Can be one of the following values:
|
||||
|
||||
* KeyWriteTimeInformation KEY_WRITE_TIME_INFORMATION
|
||||
* KeyLastWriteTimeInformation KEY_LAST_WRITE_TIME_INFORMATION
|
||||
|
||||
KeyInformation = Storage for the new information
|
||||
* KeyInformationLength = Size of the information strucure
|
||||
@@ -5457,7 +5457,7 @@ NTSTATUS
|
||||
STDCALL
|
||||
ZwSetInformationKey(
|
||||
IN HANDLE KeyHandle,
|
||||
IN CINT KeyInformationClass,
|
||||
IN KEY_SET_INFORMATION_CLASS KeyInformationClass,
|
||||
IN PVOID KeyInformation,
|
||||
IN ULONG KeyInformationLength
|
||||
);
|
||||
|
||||
@@ -471,7 +471,7 @@ CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
|
||||
|
||||
NTSTATUS
|
||||
CmiAddSubKey(IN PREGISTRY_HIVE RegistryHive,
|
||||
IN PKEY_OBJECT Parent,
|
||||
IN PKEY_OBJECT ParentKey,
|
||||
OUT PKEY_OBJECT SubKey,
|
||||
IN PUNICODE_STRING SubKeyName,
|
||||
IN ULONG TitleIndex,
|
||||
@@ -521,10 +521,11 @@ PHASH_TABLE_CELL HashBlock,
|
||||
ULONG Index);
|
||||
|
||||
NTSTATUS
|
||||
CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
|
||||
PHASH_TABLE_CELL HashBlock,
|
||||
PKEY_CELL NewKeyCell,
|
||||
BLOCK_OFFSET NKBOffset);
|
||||
CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
|
||||
PHASH_TABLE_CELL HashCell,
|
||||
BLOCK_OFFSET HashCellOffset,
|
||||
PKEY_CELL NewKeyCell,
|
||||
BLOCK_OFFSET NKBOffset);
|
||||
|
||||
NTSTATUS
|
||||
CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive,
|
||||
|
||||
@@ -1308,13 +1308,6 @@ NtSetValueKey(IN HANDLE KeyHandle,
|
||||
RtlCopyMemory(DataCell->Data, Data, DataSize);
|
||||
ValueCell->DataSize = DataSize;
|
||||
ValueCell->DataType = Type;
|
||||
|
||||
/* Update time of heap */
|
||||
if (!IsNoFileHive(RegistryHive))
|
||||
{
|
||||
NtQuerySystemTime(&pBin->DateModified);
|
||||
}
|
||||
CmiMarkBlockDirty(RegistryHive, ValueCell->DataOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1359,18 +1352,14 @@ NtSetValueKey(IN HANDLE KeyHandle,
|
||||
}
|
||||
|
||||
/* Mark link key */
|
||||
if ((_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0) &&
|
||||
(Type == REG_LINK))
|
||||
if ((Type == REG_LINK) &&
|
||||
(_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0))
|
||||
{
|
||||
KeyCell->Flags |= REG_KEY_LINK_CELL;
|
||||
CmiMarkBlockDirty(RegistryHive, KeyObject->KeyCellOffset);
|
||||
}
|
||||
|
||||
/* Update time of heap */
|
||||
if (!IsNoFileHive(RegistryHive) && CmiGetCell (RegistryHive, ValueCellOffset, &pBin))
|
||||
{
|
||||
NtQuerySystemTime(&pBin->DateModified);
|
||||
}
|
||||
NtQuerySystemTime (&KeyCell->LastWriteTime);
|
||||
CmiMarkBlockDirty (RegistryHive, KeyObject->KeyCellOffset);
|
||||
|
||||
ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
|
||||
ObDereferenceObject(KeyObject);
|
||||
@@ -1412,12 +1401,15 @@ NtDeleteValueKey (IN HANDLE KeyHandle,
|
||||
KeyObject->KeyCellOffset,
|
||||
ValueName);
|
||||
|
||||
NtQuerySystemTime (&KeyObject->KeyCell->LastWriteTime);
|
||||
CmiMarkBlockDirty (KeyObject->RegistryHive, KeyObject->KeyCellOffset);
|
||||
|
||||
/* Release hive lock */
|
||||
ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
|
||||
ExReleaseResourceLite (&KeyObject->RegistryHive->HiveResource);
|
||||
|
||||
ObDereferenceObject(KeyObject);
|
||||
ObDereferenceObject (KeyObject);
|
||||
|
||||
CmiSyncHives();
|
||||
CmiSyncHives ();
|
||||
|
||||
return Status;
|
||||
}
|
||||
@@ -1788,12 +1780,53 @@ NtSaveKey (IN HANDLE KeyHandle,
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtSetInformationKey (IN HANDLE KeyHandle,
|
||||
IN CINT KeyInformationClass,
|
||||
IN KEY_SET_INFORMATION_CLASS KeyInformationClass,
|
||||
IN PVOID KeyInformation,
|
||||
IN ULONG KeyInformationLength)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return(STATUS_NOT_IMPLEMENTED);
|
||||
PKEY_OBJECT KeyObject;
|
||||
NTSTATUS Status;
|
||||
|
||||
if (KeyInformationClass != KeyLastWriteTimeInformation)
|
||||
return STATUS_INVALID_INFO_CLASS;
|
||||
|
||||
if (KeyInformationLength != sizeof (KEY_LAST_WRITE_TIME_INFORMATION))
|
||||
return STATUS_INFO_LENGTH_MISMATCH;
|
||||
|
||||
/* Verify that the handle is valid and is a registry key */
|
||||
Status = ObReferenceObjectByHandle (KeyHandle,
|
||||
KEY_SET_VALUE,
|
||||
CmiKeyType,
|
||||
UserMode,
|
||||
(PVOID *)&KeyObject,
|
||||
NULL);
|
||||
if (!NT_SUCCESS (Status))
|
||||
{
|
||||
DPRINT ("ObReferenceObjectByHandle() failed with status %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Acquire hive lock */
|
||||
ExAcquireResourceExclusiveLite (&KeyObject->RegistryHive->HiveResource, TRUE);
|
||||
|
||||
VERIFY_KEY_OBJECT(KeyObject);
|
||||
|
||||
KeyObject->KeyCell->LastWriteTime.QuadPart =
|
||||
((PKEY_LAST_WRITE_TIME_INFORMATION)KeyInformation)->LastWriteTime.QuadPart;
|
||||
|
||||
CmiMarkBlockDirty (KeyObject->RegistryHive,
|
||||
KeyObject->KeyCellOffset);
|
||||
|
||||
/* Release hive lock */
|
||||
ExReleaseResourceLite (&KeyObject->RegistryHive->HiveResource);
|
||||
|
||||
ObDereferenceObject (KeyObject);
|
||||
|
||||
CmiSyncHives ();
|
||||
|
||||
DPRINT ("NtSaveKey() done\n");
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2323,19 +2323,18 @@ CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
|
||||
|
||||
NTSTATUS
|
||||
CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
|
||||
PKEY_OBJECT Parent,
|
||||
PKEY_OBJECT ParentKey,
|
||||
PKEY_OBJECT SubKey,
|
||||
PUNICODE_STRING SubKeyName,
|
||||
ULONG TitleIndex,
|
||||
PUNICODE_STRING Class,
|
||||
ULONG CreateOptions)
|
||||
{
|
||||
PHASH_TABLE_CELL NewHashBlock;
|
||||
PHASH_TABLE_CELL HashBlock;
|
||||
BLOCK_OFFSET NKBOffset;
|
||||
PKEY_CELL NewKeyCell;
|
||||
ULONG NewBlockSize;
|
||||
PKEY_CELL KeyCell;
|
||||
PKEY_CELL ParentKeyCell;
|
||||
PDATA_CELL ClassCell;
|
||||
NTSTATUS Status;
|
||||
USHORT NameSize;
|
||||
@@ -2343,9 +2342,9 @@ CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
|
||||
BOOLEAN Packable;
|
||||
ULONG i;
|
||||
|
||||
KeyCell = Parent->KeyCell;
|
||||
ParentKeyCell = ParentKey->KeyCell;
|
||||
|
||||
VERIFY_KEY_CELL(KeyCell);
|
||||
VERIFY_KEY_CELL(ParentKeyCell);
|
||||
|
||||
/* Skip leading backslash */
|
||||
if (SubKeyName->Buffer[0] == L'\\')
|
||||
@@ -2443,16 +2442,16 @@ CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
|
||||
SubKey->KeyCellOffset = NKBOffset;
|
||||
|
||||
/* Don't modify hash table if key is located in a pointer-based hive and parent key is not */
|
||||
if (IsPointerHive(RegistryHive) && (!IsPointerHive(Parent->RegistryHive)))
|
||||
if (IsPointerHive(RegistryHive) && (!IsPointerHive(ParentKey->RegistryHive)))
|
||||
{
|
||||
return(Status);
|
||||
}
|
||||
|
||||
if (KeyCell->HashTableOffset == (ULONG_PTR) -1)
|
||||
if (ParentKeyCell->HashTableOffset == (ULONG_PTR) -1)
|
||||
{
|
||||
Status = CmiAllocateHashTableCell (RegistryHive,
|
||||
&HashBlock,
|
||||
&KeyCell->HashTableOffset,
|
||||
&ParentKeyCell->HashTableOffset,
|
||||
REG_INIT_HASH_TABLE_SIZE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
@@ -2462,16 +2461,17 @@ CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
|
||||
else
|
||||
{
|
||||
HashBlock = CmiGetCell (RegistryHive,
|
||||
KeyCell->HashTableOffset,
|
||||
ParentKeyCell->HashTableOffset,
|
||||
NULL);
|
||||
if (HashBlock == NULL)
|
||||
{
|
||||
DPRINT("CmiGetBlock() failed\n");
|
||||
DPRINT("CmiGetCell() failed\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
if (((KeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
|
||||
if (((ParentKeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
|
||||
{
|
||||
PHASH_TABLE_CELL NewHashBlock;
|
||||
BLOCK_OFFSET HTOffset;
|
||||
|
||||
/* Reallocate the hash table cell */
|
||||
@@ -2492,21 +2492,25 @@ CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
|
||||
sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
|
||||
CmiDestroyCell (RegistryHive,
|
||||
HashBlock,
|
||||
KeyCell->HashTableOffset);
|
||||
KeyCell->HashTableOffset = HTOffset;
|
||||
ParentKeyCell->HashTableOffset);
|
||||
ParentKeyCell->HashTableOffset = HTOffset;
|
||||
HashBlock = NewHashBlock;
|
||||
}
|
||||
}
|
||||
|
||||
Status = CmiAddKeyToHashTable(RegistryHive,
|
||||
HashBlock,
|
||||
ParentKeyCell->HashTableOffset,
|
||||
NewKeyCell,
|
||||
NKBOffset);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
KeyCell->NumberOfSubKeys++;
|
||||
ParentKeyCell->NumberOfSubKeys++;
|
||||
}
|
||||
|
||||
NtQuerySystemTime (&ParentKeyCell->LastWriteTime);
|
||||
CmiMarkBlockDirty (RegistryHive, ParentKey->KeyCellOffset);
|
||||
|
||||
return(Status);
|
||||
}
|
||||
|
||||
@@ -2533,7 +2537,7 @@ CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
|
||||
NULL);
|
||||
if (ValueList == NULL)
|
||||
{
|
||||
DPRINT("CmiGetBlock() failed\n");
|
||||
DPRINT("CmiGetCell() failed\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
@@ -2555,7 +2559,7 @@ CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
|
||||
NULL);
|
||||
if (DataCell == NULL)
|
||||
{
|
||||
DPRINT("CmiGetBlock() failed\n");
|
||||
DPRINT("CmiGetCell() failed\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
@@ -2594,7 +2598,7 @@ CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
|
||||
NULL);
|
||||
if (HashBlock == NULL)
|
||||
{
|
||||
DPRINT("CmiGetBlock() failed\n");
|
||||
DPRINT("CmiGetCell() failed\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
DPRINT("ParentKey HashBlock %p\n", HashBlock)
|
||||
@@ -2617,7 +2621,7 @@ CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
|
||||
NULL);
|
||||
if (HashBlock == NULL)
|
||||
{
|
||||
DPRINT("CmiGetBlock() failed\n");
|
||||
DPRINT("CmiGetCell() failed\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
DPRINT("SubKey HashBlock %p\n", HashBlock)
|
||||
@@ -2645,7 +2649,7 @@ CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
|
||||
NULL);
|
||||
if (HashBlock == NULL)
|
||||
{
|
||||
DPRINT("CmiGetBlock() failed\n");
|
||||
DPRINT("CmiGetCell() failed\n");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
DPRINT("ParentKey HashBlock %p\n", HashBlock)
|
||||
@@ -2994,24 +2998,26 @@ CmiGetKeyFromHashByIndex(PREGISTRY_HIVE RegistryHive,
|
||||
|
||||
NTSTATUS
|
||||
CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
|
||||
PHASH_TABLE_CELL HashBlock,
|
||||
PHASH_TABLE_CELL HashCell,
|
||||
BLOCK_OFFSET HashCellOffset,
|
||||
PKEY_CELL NewKeyCell,
|
||||
BLOCK_OFFSET NKBOffset)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
for (i = 0; i < HashBlock->HashTableSize; i++)
|
||||
for (i = 0; i < HashCell->HashTableSize; i++)
|
||||
{
|
||||
if (HashBlock->Table[i].KeyOffset == 0)
|
||||
if (HashCell->Table[i].KeyOffset == 0)
|
||||
{
|
||||
HashBlock->Table[i].KeyOffset = NKBOffset;
|
||||
HashBlock->Table[i].HashValue = 0;
|
||||
HashCell->Table[i].KeyOffset = NKBOffset;
|
||||
HashCell->Table[i].HashValue = 0;
|
||||
if (NewKeyCell->Flags & REG_KEY_NAME_PACKED)
|
||||
{
|
||||
RtlCopyMemory(&HashBlock->Table[i].HashValue,
|
||||
RtlCopyMemory(&HashCell->Table[i].HashValue,
|
||||
NewKeyCell->Name,
|
||||
min(NewKeyCell->NameSize, sizeof(ULONG)));
|
||||
}
|
||||
CmiMarkBlockDirty(RegistryHive, HashCellOffset);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -3260,7 +3266,8 @@ CmiAllocateCell (PREGISTRY_HIVE RegistryHive,
|
||||
else
|
||||
{
|
||||
RtlZeroMemory(NewCell, CellSize);
|
||||
NewCell->CellSize = CellSize;
|
||||
NewCell->CellSize = -CellSize;
|
||||
|
||||
*Cell = NewCell;
|
||||
if (CellOffset != NULL)
|
||||
*CellOffset = (BLOCK_OFFSET) NewCell;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $Id: registry.c,v 1.111 2003/10/12 17:05:44 hbirr Exp $
|
||||
/* $Id: registry.c,v 1.112 2003/10/13 20:53:42 ekohl Exp $
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
@@ -980,6 +980,13 @@ CmShutdownRegistry(VOID)
|
||||
/* Stop automatic hive synchronization */
|
||||
CmiHiveSyncEnabled = FALSE;
|
||||
|
||||
/* Cancel pending hive synchronization */
|
||||
if (CmiHiveSyncPending == TRUE)
|
||||
{
|
||||
KeCancelTimer(&CmiHiveSyncTimer);
|
||||
CmiHiveSyncPending = FALSE;
|
||||
}
|
||||
|
||||
/* Acquire hive list lock exclusively */
|
||||
ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <internal/ob.h>
|
||||
#include <internal/registry.h>
|
||||
#include <ntos/minmax.h>
|
||||
#include <reactos/bugcodes.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
@@ -269,13 +270,15 @@ CmiObjectCreate(PVOID ObjectBody,
|
||||
VOID STDCALL
|
||||
CmiObjectDelete(PVOID DeletedObject)
|
||||
{
|
||||
PKEY_OBJECT ParentKeyObject;
|
||||
PKEY_OBJECT KeyObject;
|
||||
|
||||
DPRINT("Delete key object (%p)\n", DeletedObject);
|
||||
|
||||
KeyObject = (PKEY_OBJECT) DeletedObject;
|
||||
|
||||
ObReferenceObject(KeyObject->ParentKey);
|
||||
ParentKeyObject = KeyObject->ParentKey;
|
||||
|
||||
ObReferenceObject (ParentKeyObject);
|
||||
|
||||
if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject)))
|
||||
{
|
||||
@@ -289,24 +292,31 @@ CmiObjectDelete(PVOID DeletedObject)
|
||||
DPRINT("delete really key\n");
|
||||
|
||||
CmiRemoveSubKey(KeyObject->RegistryHive,
|
||||
KeyObject->ParentKey,
|
||||
ParentKeyObject,
|
||||
KeyObject);
|
||||
|
||||
if (!IsNoFileHive(KeyObject->RegistryHive))
|
||||
NtQuerySystemTime (&ParentKeyObject->KeyCell->LastWriteTime);
|
||||
CmiMarkBlockDirty (ParentKeyObject->RegistryHive,
|
||||
ParentKeyObject->KeyCellOffset);
|
||||
|
||||
if (!IsNoFileHive (KeyObject->RegistryHive) ||
|
||||
!IsNoFileHive (ParentKeyObject->RegistryHive))
|
||||
{
|
||||
CmiSyncHives();
|
||||
CmiSyncHives ();
|
||||
}
|
||||
}
|
||||
ObDereferenceObject(KeyObject->ParentKey);
|
||||
|
||||
ObDereferenceObject (ParentKeyObject);
|
||||
|
||||
if (KeyObject->NumberOfSubKeys)
|
||||
{
|
||||
KEBUGCHECK(0);
|
||||
KEBUGCHECK(REGISTRY_ERROR);
|
||||
}
|
||||
|
||||
if (KeyObject->SizeOfSubKeys)
|
||||
{
|
||||
ExFreePool(KeyObject->SubKeys);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user