mirror of
https://github.com/reactos/reactos.git
synced 2024-09-28 21:44:31 +00:00
[CMLIB]
- Now that both FreeLdr and MKHIVE use the regular (aka. the "NT-style public") CMLIB functions, get rid of the "old-style public" cmlib functions, with the exception of CmCreateRootNode and CmPrepareHive which remain for now due to a slight different implementation difference between NT and ours. Remove the cmtools.c file containing those old functions. - Remove the now-deprecated VALUE_LIST_CELL structure (which was an old version of CELL_DATA:KeyList). - When freeing hive bins (in HvpFreeHiveBins), use the storage number count stored in the hive instead of a constant value. - Flat hives have only one storage type (they are read-only and reside only in memory). CORE-10802 CORE-10793 svn path=/trunk/; revision=70605
This commit is contained in:
parent
17c6bfd956
commit
8c2454ea74
|
@ -7,7 +7,6 @@ list(APPEND SOURCE
|
||||||
cminit.c
|
cminit.c
|
||||||
cmindex.c
|
cmindex.c
|
||||||
cmname.c
|
cmname.c
|
||||||
cmtools.c
|
|
||||||
cmvalue.c
|
cmvalue.c
|
||||||
hivebin.c
|
hivebin.c
|
||||||
hivecell.c
|
hivecell.c
|
||||||
|
|
|
@ -27,16 +27,16 @@
|
||||||
//
|
//
|
||||||
// CM_KEY_NODE Flags
|
// CM_KEY_NODE Flags
|
||||||
//
|
//
|
||||||
#define KEY_IS_VOLATILE 0x01
|
#define KEY_IS_VOLATILE 0x0001
|
||||||
#define KEY_HIVE_EXIT 0x02
|
#define KEY_HIVE_EXIT 0x0002
|
||||||
#define KEY_HIVE_ENTRY 0x04
|
#define KEY_HIVE_ENTRY 0x0004
|
||||||
#define KEY_NO_DELETE 0x08
|
#define KEY_NO_DELETE 0x0008
|
||||||
#define KEY_SYM_LINK 0x10
|
#define KEY_SYM_LINK 0x0010
|
||||||
#define KEY_COMP_NAME 0x20
|
#define KEY_COMP_NAME 0x0020
|
||||||
#define KEY_PREFEF_HANDLE 0x40
|
#define KEY_PREFEF_HANDLE 0x0040
|
||||||
#define KEY_VIRT_MIRRORED 0x80
|
#define KEY_VIRT_MIRRORED 0x0080
|
||||||
#define KEY_VIRT_TARGET 0x100
|
#define KEY_VIRT_TARGET 0x0100
|
||||||
#define KEY_VIRTUAL_STORE 0x200
|
#define KEY_VIRTUAL_STORE 0x0200
|
||||||
|
|
||||||
//
|
//
|
||||||
// CM_KEY_VALUE Flags
|
// CM_KEY_VALUE Flags
|
||||||
|
@ -67,7 +67,7 @@ typedef struct _CM_VIEW_OF_FILE
|
||||||
} CM_VIEW_OF_FILE, *PCM_VIEW_OF_FILE;
|
} CM_VIEW_OF_FILE, *PCM_VIEW_OF_FILE;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Children of Key Notes
|
// Children of Key Nodes
|
||||||
//
|
//
|
||||||
typedef struct _CHILD_LIST
|
typedef struct _CHILD_LIST
|
||||||
{
|
{
|
||||||
|
@ -116,14 +116,6 @@ typedef struct _CM_KEY_NODE
|
||||||
WCHAR Name[ANYSIZE_ARRAY];
|
WCHAR Name[ANYSIZE_ARRAY];
|
||||||
} CM_KEY_NODE, *PCM_KEY_NODE;
|
} CM_KEY_NODE, *PCM_KEY_NODE;
|
||||||
|
|
||||||
//
|
|
||||||
// Value List
|
|
||||||
//
|
|
||||||
typedef struct _VALUE_LIST_CELL
|
|
||||||
{
|
|
||||||
HCELL_INDEX ValueOffset[ANYSIZE_ARRAY];
|
|
||||||
} VALUE_LIST_CELL, *PVALUE_LIST_CELL;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Value Key
|
// Value Key
|
||||||
//
|
//
|
||||||
|
|
|
@ -37,7 +37,11 @@ CmCreateRootNode(
|
||||||
|
|
||||||
/* Get the key cell */
|
/* Get the key cell */
|
||||||
KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, RootCellIndex);
|
KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, RootCellIndex);
|
||||||
if (!KeyCell) return FALSE;
|
if (!KeyCell)
|
||||||
|
{
|
||||||
|
HvFreeCell(Hive, RootCellIndex);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup the cell */
|
/* Setup the cell */
|
||||||
KeyCell->Signature = CM_KEY_NODE_SIGNATURE;
|
KeyCell->Signature = CM_KEY_NODE_SIGNATURE;
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define strncasecmp _strnicmp
|
#define strncasecmp _strnicmp
|
||||||
#define strcasecmp _stricmp
|
#define strcasecmp _stricmp
|
||||||
#endif//_WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
#if (!defined(_MSC_VER) || (_MSC_VER < 1500))
|
#if (!defined(_MSC_VER) || (_MSC_VER < 1500))
|
||||||
#define _In_
|
#define _In_
|
||||||
|
@ -68,6 +68,7 @@
|
||||||
#define USHORT_MAX USHRT_MAX
|
#define USHORT_MAX USHRT_MAX
|
||||||
|
|
||||||
#define OBJ_NAME_PATH_SEPARATOR ((WCHAR)L'\\')
|
#define OBJ_NAME_PATH_SEPARATOR ((WCHAR)L'\\')
|
||||||
|
#define UNICODE_NULL ((WCHAR)0)
|
||||||
|
|
||||||
VOID NTAPI
|
VOID NTAPI
|
||||||
KeQuerySystemTime(
|
KeQuerySystemTime(
|
||||||
|
@ -161,7 +162,7 @@
|
||||||
//
|
//
|
||||||
// These define the Debug Masks Supported
|
// These define the Debug Masks Supported
|
||||||
//
|
//
|
||||||
#define CMLIB_HCELL_DEBUG 0x01
|
#define CMLIB_HCELL_DEBUG 0x01
|
||||||
|
|
||||||
#ifndef ROUND_UP
|
#ifndef ROUND_UP
|
||||||
#define ROUND_UP(a,b) ((((a)+(b)-1)/(b))*(b))
|
#define ROUND_UP(a,b) ((((a)+(b)-1)/(b))*(b))
|
||||||
|
@ -191,12 +192,17 @@
|
||||||
#include "hivedata.h"
|
#include "hivedata.h"
|
||||||
#include "cmdata.h"
|
#include "cmdata.h"
|
||||||
|
|
||||||
#if defined(_TYPEDEFS_HOST_H) || defined(__FREELDR_H)
|
#if defined(_TYPEDEFS_HOST_H) || defined(__FREELDR_H) // || defined(_BLDR_)
|
||||||
|
|
||||||
#define PCM_KEY_SECURITY_CACHE_ENTRY PVOID
|
#define PCM_KEY_SECURITY_CACHE_ENTRY PVOID
|
||||||
#define PCM_KEY_CONTROL_BLOCK PVOID
|
#define PCM_KEY_CONTROL_BLOCK PVOID
|
||||||
#define CMP_SECURITY_HASH_LISTS 64
|
#define PCM_CELL_REMAP_BLOCK PVOID
|
||||||
#define PCM_CELL_REMAP_BLOCK PVOID
|
|
||||||
|
// See also ntoskrnl/include/internal/cm.h
|
||||||
|
#define CMP_SECURITY_HASH_LISTS 64
|
||||||
|
|
||||||
|
// #endif // Commented out until one finds a way to properly include
|
||||||
|
// this header in freeldr and in ntoskrnl.
|
||||||
|
|
||||||
//
|
//
|
||||||
// Use Count Log and Entry
|
// Use Count Log and Entry
|
||||||
|
@ -263,7 +269,7 @@ typedef struct _CMHIVE
|
||||||
PKTHREAD CreatorOwner;
|
PKTHREAD CreatorOwner;
|
||||||
} CMHIVE, *PCMHIVE;
|
} CMHIVE, *PCMHIVE;
|
||||||
|
|
||||||
#endif
|
#endif // See comment above
|
||||||
|
|
||||||
typedef struct _HV_HIVE_CELL_PAIR
|
typedef struct _HV_HIVE_CELL_PAIR
|
||||||
{
|
{
|
||||||
|
@ -466,55 +472,9 @@ VOID CMAPI
|
||||||
CmPrepareHive(
|
CmPrepareHive(
|
||||||
PHHIVE RegistryHive);
|
PHHIVE RegistryHive);
|
||||||
|
|
||||||
BOOLEAN
|
|
||||||
NTAPI
|
|
||||||
CmCompareHash(
|
|
||||||
IN PCUNICODE_STRING KeyName,
|
|
||||||
IN PCHAR HashString,
|
|
||||||
IN BOOLEAN CaseInsensitive);
|
|
||||||
|
|
||||||
BOOLEAN
|
|
||||||
NTAPI
|
|
||||||
CmComparePackedNames(
|
|
||||||
IN PCUNICODE_STRING Name,
|
|
||||||
IN PVOID NameBuffer,
|
|
||||||
IN USHORT NameBufferSize,
|
|
||||||
IN BOOLEAN NamePacked,
|
|
||||||
IN BOOLEAN CaseInsensitive);
|
|
||||||
|
|
||||||
BOOLEAN
|
|
||||||
NTAPI
|
|
||||||
CmCompareKeyName(
|
|
||||||
IN PCM_KEY_NODE KeyCell,
|
|
||||||
IN PCUNICODE_STRING KeyName,
|
|
||||||
IN BOOLEAN CaseInsensitive);
|
|
||||||
|
|
||||||
BOOLEAN
|
|
||||||
NTAPI
|
|
||||||
CmCompareKeyValueName(
|
|
||||||
IN PCM_KEY_VALUE ValueCell,
|
|
||||||
IN PCUNICODE_STRING KeyName,
|
|
||||||
IN BOOLEAN CaseInsensitive);
|
|
||||||
|
|
||||||
ULONG
|
|
||||||
NTAPI
|
|
||||||
CmCopyKeyName(
|
|
||||||
_In_ PCM_KEY_NODE KeyNode,
|
|
||||||
_Out_ PWCHAR KeyNameBuffer,
|
|
||||||
_Inout_ ULONG BufferLength);
|
|
||||||
|
|
||||||
ULONG
|
|
||||||
NTAPI
|
|
||||||
CmCopyKeyValueName(
|
|
||||||
_In_ PCM_KEY_VALUE ValueCell,
|
|
||||||
_Out_ PWCHAR ValueNameBuffer,
|
|
||||||
_Inout_ ULONG BufferLength);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* NT-style Public Cm functions */
|
/* NT-style Public Cm functions */
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Cell Index Routines
|
// Cell Index Routines
|
||||||
//
|
//
|
||||||
|
@ -615,8 +575,8 @@ CmpFindNameInList(
|
||||||
IN PHHIVE Hive,
|
IN PHHIVE Hive,
|
||||||
IN PCHILD_LIST ChildList,
|
IN PCHILD_LIST ChildList,
|
||||||
IN PUNICODE_STRING Name,
|
IN PUNICODE_STRING Name,
|
||||||
IN PULONG ChildIndex,
|
OUT PULONG ChildIndex,
|
||||||
IN PHCELL_INDEX CellIndex
|
OUT PHCELL_INDEX CellIndex
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -695,7 +655,7 @@ NTAPI
|
||||||
CmpGetValueData(
|
CmpGetValueData(
|
||||||
IN PHHIVE Hive,
|
IN PHHIVE Hive,
|
||||||
IN PCM_KEY_VALUE Value,
|
IN PCM_KEY_VALUE Value,
|
||||||
IN PULONG Length,
|
OUT PULONG Length,
|
||||||
OUT PVOID *Buffer,
|
OUT PVOID *Buffer,
|
||||||
OUT PBOOLEAN BufferAllocated,
|
OUT PBOOLEAN BufferAllocated,
|
||||||
OUT PHCELL_INDEX CellToRelease
|
OUT PHCELL_INDEX CellToRelease
|
||||||
|
|
|
@ -1,222 +0,0 @@
|
||||||
/*
|
|
||||||
* PROJECT: Registry manipulation library
|
|
||||||
* LICENSE: GPL - See COPYING in the top level directory
|
|
||||||
* COPYRIGHT: Copyright 2005 Filip Navara <navaraf@reactos.org>
|
|
||||||
* Copyright 2001 - 2005 Eric Kohl
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "cmlib.h"
|
|
||||||
#define NDEBUG
|
|
||||||
#include <debug.h>
|
|
||||||
|
|
||||||
BOOLEAN
|
|
||||||
NTAPI
|
|
||||||
CmCompareHash(
|
|
||||||
IN PCUNICODE_STRING KeyName,
|
|
||||||
IN PCHAR HashString,
|
|
||||||
IN BOOLEAN CaseInsensitive)
|
|
||||||
{
|
|
||||||
CHAR Buffer[4];
|
|
||||||
|
|
||||||
Buffer[0] = (KeyName->Length >= 2) ? (CHAR)KeyName->Buffer[0] : 0;
|
|
||||||
Buffer[1] = (KeyName->Length >= 4) ? (CHAR)KeyName->Buffer[1] : 0;
|
|
||||||
Buffer[2] = (KeyName->Length >= 6) ? (CHAR)KeyName->Buffer[2] : 0;
|
|
||||||
Buffer[3] = (KeyName->Length >= 8) ? (CHAR)KeyName->Buffer[3] : 0;
|
|
||||||
|
|
||||||
if (CaseInsensitive)
|
|
||||||
{
|
|
||||||
return (strncasecmp(Buffer, HashString, 4) == 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return (strncmp(Buffer, HashString, 4) == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOLEAN
|
|
||||||
NTAPI
|
|
||||||
CmComparePackedNames(
|
|
||||||
IN PCUNICODE_STRING CompareName,
|
|
||||||
IN PVOID Name,
|
|
||||||
IN USHORT NameLength,
|
|
||||||
IN BOOLEAN NamePacked,
|
|
||||||
IN BOOLEAN CaseInsensitive)
|
|
||||||
{
|
|
||||||
ULONG i;
|
|
||||||
|
|
||||||
if (NamePacked)
|
|
||||||
{
|
|
||||||
PUCHAR PackedName = (PUCHAR)Name;
|
|
||||||
|
|
||||||
if (CompareName->Length != NameLength * sizeof(WCHAR))
|
|
||||||
{
|
|
||||||
//DPRINT1("Length doesn'T match %lu / %lu\n", CompareName->Length, NameLength);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CaseInsensitive)
|
|
||||||
{
|
|
||||||
for (i = 0; i < CompareName->Length / sizeof(WCHAR); i++)
|
|
||||||
{
|
|
||||||
//DbgPrint("%c/%c,",
|
|
||||||
// RtlUpcaseUnicodeChar(CompareName->Buffer[i]),
|
|
||||||
// RtlUpcaseUnicodeChar(PackedName[i]));
|
|
||||||
if (RtlUpcaseUnicodeChar(CompareName->Buffer[i]) !=
|
|
||||||
RtlUpcaseUnicodeChar(PackedName[i]))
|
|
||||||
{
|
|
||||||
//DbgPrint("\nFailed!\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//DbgPrint("\nSuccess!\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (i = 0; i < CompareName->Length / sizeof(WCHAR); i++)
|
|
||||||
{
|
|
||||||
if (CompareName->Buffer[i] != PackedName[i])
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PWCHAR UnicodeName = (PWCHAR)Name;
|
|
||||||
|
|
||||||
if (CompareName->Length != NameLength)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (CaseInsensitive)
|
|
||||||
{
|
|
||||||
for (i = 0; i < CompareName->Length / sizeof(WCHAR); i++)
|
|
||||||
{
|
|
||||||
if (RtlUpcaseUnicodeChar(CompareName->Buffer[i]) !=
|
|
||||||
RtlUpcaseUnicodeChar(UnicodeName[i]))
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (i = 0; i < CompareName->Length / sizeof(WCHAR); i++)
|
|
||||||
{
|
|
||||||
if (CompareName->Buffer[i] != UnicodeName[i])
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BOOLEAN
|
|
||||||
NTAPI
|
|
||||||
CmCompareKeyName(
|
|
||||||
IN PCM_KEY_NODE KeyNode,
|
|
||||||
IN PCUNICODE_STRING KeyName,
|
|
||||||
IN BOOLEAN CaseInsensitive)
|
|
||||||
{
|
|
||||||
ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
|
|
||||||
return CmComparePackedNames(KeyName,
|
|
||||||
KeyNode->Name,
|
|
||||||
KeyNode->NameLength,
|
|
||||||
(KeyNode->Flags & KEY_COMP_NAME) ? TRUE : FALSE,
|
|
||||||
CaseInsensitive);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOLEAN
|
|
||||||
NTAPI
|
|
||||||
CmCompareKeyValueName(
|
|
||||||
IN PCM_KEY_VALUE ValueCell,
|
|
||||||
IN PCUNICODE_STRING ValueName,
|
|
||||||
IN BOOLEAN CaseInsensitive)
|
|
||||||
{
|
|
||||||
ASSERT(ValueCell->Signature == CM_KEY_VALUE_SIGNATURE);
|
|
||||||
return CmComparePackedNames(ValueName,
|
|
||||||
ValueCell->Name,
|
|
||||||
ValueCell->NameLength,
|
|
||||||
(ValueCell->Flags & VALUE_COMP_NAME) ? TRUE : FALSE,
|
|
||||||
CaseInsensitive);
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG
|
|
||||||
NTAPI
|
|
||||||
CmCopyPackedName(
|
|
||||||
_Out_ PWCHAR Buffer,
|
|
||||||
_In_ ULONG BufferLength,
|
|
||||||
_In_ PVOID Name,
|
|
||||||
_In_ USHORT NameLength,
|
|
||||||
_In_ BOOLEAN NamePacked)
|
|
||||||
{
|
|
||||||
ULONG CharCount, i;
|
|
||||||
ASSERT(Name != 0);
|
|
||||||
ASSERT(NameLength != 0);
|
|
||||||
|
|
||||||
if (NamePacked)
|
|
||||||
{
|
|
||||||
NameLength *= sizeof(WCHAR);
|
|
||||||
CharCount = min(BufferLength, NameLength) / sizeof(WCHAR);
|
|
||||||
|
|
||||||
if (Buffer != NULL)
|
|
||||||
{
|
|
||||||
PUCHAR PackedName = (PUCHAR)Name;
|
|
||||||
|
|
||||||
for (i = 0; i < CharCount; i++)
|
|
||||||
{
|
|
||||||
Buffer[i] = PackedName[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CharCount = min(BufferLength, NameLength) / sizeof(WCHAR);
|
|
||||||
|
|
||||||
if (Buffer != NULL)
|
|
||||||
{
|
|
||||||
PWCHAR UnicodeName = (PWCHAR)Name;
|
|
||||||
|
|
||||||
for (i = 0; i < CharCount; i++)
|
|
||||||
{
|
|
||||||
Buffer[i] = UnicodeName[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BufferLength >= NameLength + sizeof(WCHAR))
|
|
||||||
{
|
|
||||||
Buffer[NameLength / sizeof(WCHAR)] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return NameLength + sizeof(WCHAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG
|
|
||||||
NTAPI
|
|
||||||
CmCopyKeyName(
|
|
||||||
_In_ PCM_KEY_NODE KeyNode,
|
|
||||||
_Out_ PWCHAR KeyNameBuffer,
|
|
||||||
_Inout_ ULONG BufferLength)
|
|
||||||
{
|
|
||||||
ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
|
|
||||||
return CmCopyPackedName(KeyNameBuffer,
|
|
||||||
BufferLength,
|
|
||||||
KeyNode->Name,
|
|
||||||
KeyNode->NameLength,
|
|
||||||
(KeyNode->Flags & KEY_COMP_NAME) ? TRUE : FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG
|
|
||||||
NTAPI
|
|
||||||
CmCopyKeyValueName(
|
|
||||||
_In_ PCM_KEY_VALUE ValueCell,
|
|
||||||
_Out_ PWCHAR ValueNameBuffer,
|
|
||||||
_Inout_ ULONG BufferLength)
|
|
||||||
{
|
|
||||||
ASSERT(ValueCell->Signature == CM_KEY_VALUE_SIGNATURE);
|
|
||||||
return CmCopyPackedName(ValueNameBuffer,
|
|
||||||
BufferLength,
|
|
||||||
ValueCell->Name,
|
|
||||||
ValueCell->NameLength,
|
|
||||||
(ValueCell->Flags & VALUE_COMP_NAME) ? TRUE : FALSE);
|
|
||||||
}
|
|
|
@ -57,7 +57,7 @@ HvpFreeHiveBins(
|
||||||
PHBIN Bin;
|
PHBIN Bin;
|
||||||
ULONG Storage;
|
ULONG Storage;
|
||||||
|
|
||||||
for (Storage = Stable; Storage < HTYPE_COUNT; Storage++)
|
for (Storage = 0; Storage < Hive->StorageTypeCount; Storage++)
|
||||||
{
|
{
|
||||||
Bin = NULL;
|
Bin = NULL;
|
||||||
for (i = 0; i < Hive->Storage[Storage].Length; i++)
|
for (i = 0; i < Hive->Storage[Storage].Length; i++)
|
||||||
|
@ -354,6 +354,8 @@ HvpInitializeFlatHive(
|
||||||
Hive->Flat = TRUE;
|
Hive->Flat = TRUE;
|
||||||
Hive->ReadOnly = TRUE;
|
Hive->ReadOnly = TRUE;
|
||||||
|
|
||||||
|
Hive->StorageTypeCount = 1;
|
||||||
|
|
||||||
/* Set default boot type */
|
/* Set default boot type */
|
||||||
ChunkBase->BootType = 0;
|
ChunkBase->BootType = 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue