8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 10:00:38 +01:00

Make UID output comply RFC 4122 (#306)

* Make UID output comply RFC 4122

* Update format specifier to explicit unsigned char type
This commit is contained in:
Dimitry Sibiryakov 2021-01-27 19:07:27 +01:00 committed by GitHub
parent c535672e55
commit 2a41326de2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 70 additions and 76 deletions

View File

@ -31,53 +31,52 @@
#include <stdlib.h>
#include <stdio.h>
#ifdef WIN_NT
#include <rpc.h>
#else
#include "fb_types.h"
struct UUID // Compatible with Win32 UUID struct layout.
{
ULONG Data1;
USHORT Data2;
USHORT Data3;
UCHAR Data4[8];
};
#endif
namespace Firebird {
typedef UUID Guid;
const int GUID_BUFF_SIZE = 39;
const int GUID_BODY_SIZE = 36;
const char* const GUID_LEGACY_FORMAT =
"{%04hX%04hX-%04hX-%04hX-%04hX-%04hX%04hX%04hX}";
const char* const GUID_NEW_FORMAT =
"{%02hX%02hX%02hX%02hX-%02hX%02hX-%02hX%02hX-%02hX%02hX-%02hX%02hX%02hX%02hX%02hX%02hX}";
struct Guid
{
union
{
USHORT data[8];
ULONG alignment; // makes sure C-cast to Win32GUID works correctly
};
};
struct Win32GUID // Compatible with Win32 GUID struct layout.
{
ULONG data1;
USHORT data2;
USHORT data3;
UCHAR data4[8];
};
// Some versions of MSVC cannot recognize hh specifier but MSVC 2015 has it.
const char* const GUID_FORMAT =
"{%08X-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}";
void GenerateRandomBytes(void* buffer, FB_SIZE_T size);
// Generates platform-depended UUID compatible with RFC 4122
void GenerateGuid(Guid* guid);
// These functions receive buffers of at least GUID_BUFF_SIZE length.
// Warning: they are BROKEN in little-endian and should not be used on new code.
inline void GuidToString(char* buffer, const Guid* guid)
{
sprintf(buffer, GUID_LEGACY_FORMAT,
guid->data[0], guid->data[1], guid->data[2], guid->data[3],
guid->data[4], guid->data[5], guid->data[6], guid->data[7]);
sprintf(buffer, GUID_FORMAT,
guid->Data1, guid->Data2, guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
}
inline void StringToGuid(Guid* guid, const char* buffer)
{
sscanf(buffer, GUID_LEGACY_FORMAT,
&guid->data[0], &guid->data[1], &guid->data[2], &guid->data[3],
&guid->data[4], &guid->data[5], &guid->data[6], &guid->data[7]);
sscanf(buffer, GUID_FORMAT,
&guid->Data1, &guid->Data2, &guid->Data3,
&guid->Data4[0], &guid->Data4[1], &guid->Data4[2], &guid->Data4[3],
&guid->Data4[4], &guid->Data4[5], &guid->Data4[6], &guid->Data4[7]);
}
} // namespace

View File

@ -71,9 +71,8 @@ void GenerateGuid(Guid* guid)
{
GenerateRandomBytes(guid, sizeof(Guid));
Win32GUID* wg = (Win32GUID*) guid;
wg->data3 = (4 << 12) | (wg->data3 & 0xFFF); // version 4
wg->data4[0] = 0x80 | (wg->data4[0] & 0x3F); // variant
guid->Data3 = (4 << 12) | (guid->Data3 & 0xFFF); // version 4
guid->Data4[0] = 0x80 | (guid->Data4[0] & 0x3F); // variant
}

View File

@ -76,7 +76,7 @@ void GenerateRandomBytes(void* buffer, FB_SIZE_T size)
void GenerateGuid(Guid* guid)
{
const HRESULT error = CoCreateGuid((GUID*) guid);
const HRESULT error = CoCreateGuid(guid);
if (!SUCCEEDED(error))
Firebird::system_call_failed::raise("CoCreateGuid", error);
}

View File

@ -354,7 +354,7 @@ namespace Jrd
if (readOnly())
return;
if (!dbb_guid.alignment) // hackery way to check whether it was loaded
if (!dbb_guid.Data1) // It would be better to full check but one field should be enough
{
GenerateGuid(&dbb_guid);
PAG_set_db_guid(tdbb, dbb_guid);

View File

@ -2346,26 +2346,20 @@ dsc* evlCharToUuid(thread_db* tdbb, const SysFunction* function, const NestValue
}
}
// convert to binary representation
char buffer[GUID_BUFF_SIZE];
buffer[0] = '{';
buffer[37] = '}';
buffer[38] = '\0';
memcpy(buffer + 1, data, GUID_BODY_SIZE);
#if defined(_MSC_VER) && _MSC_VER < 1900
#pragma message("Support of hh size modifier is not sure")
#endif
USHORT bytes[16];
sscanf(buffer, GUID_NEW_FORMAT,
UCHAR bytes[16];
sscanf(reinterpret_cast<const char*>(data),
"%02hhX%02hhX%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
&bytes[0], &bytes[1], &bytes[2], &bytes[3],
&bytes[4], &bytes[5], &bytes[6], &bytes[7],
&bytes[8], &bytes[9], &bytes[10], &bytes[11],
&bytes[12], &bytes[13], &bytes[14], &bytes[15]);
UCHAR resultData[16];
for (unsigned i = 0; i < 16; ++i)
resultData[i] = (UCHAR) bytes[i];
dsc result;
result.makeText(16, ttype_binary, resultData);
result.makeText(16, ttype_binary, bytes);
EVL_make_value(tdbb, &result, impure);
return &impure->vlu_desc;
@ -4111,29 +4105,30 @@ dsc* evlGenUuid(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
{
fb_assert(args.getCount() == 0);
Guid fbguid;
fb_assert(sizeof(fbguid.data) == 16);
Guid guid;
static_assert(sizeof(guid) == 16, "Guid size mismatch");
GenerateGuid(&fbguid);
Win32GUID* guid = (Win32GUID*)&fbguid;
GenerateGuid(&guid);
// Convert platform-depended UUID into platform-independent form
// according to RFC 4122
UCHAR data[16];
data[0] = (guid->data1 >> 24) & 0xFF;
data[1] = (guid->data1 >> 16) & 0xFF;
data[2] = (guid->data1 >> 8) & 0xFF;
data[3] = guid->data1 & 0xFF;
data[4] = (guid->data2 >> 8) & 0xFF;
data[5] = guid->data2 & 0xFF;
data[6] = (guid->data3 >> 8) & 0xFF;
data[7] = guid->data3 & 0xFF;
data[8] = guid->data4[0];
data[9] = guid->data4[1];
data[10] = guid->data4[2];
data[11] = guid->data4[3];
data[12] = guid->data4[4];
data[13] = guid->data4[5];
data[14] = guid->data4[6];
data[15] = guid->data4[7];
data[0] = (guid.Data1 >> 24) & 0xFF;
data[1] = (guid.Data1 >> 16) & 0xFF;
data[2] = (guid.Data1 >> 8) & 0xFF;
data[3] = guid.Data1 & 0xFF;
data[4] = (guid.Data2 >> 8) & 0xFF;
data[5] = guid.Data2 & 0xFF;
data[6] = (guid.Data3 >> 8) & 0xFF;
data[7] = guid.Data3 & 0xFF;
data[8] = guid.Data4[0];
data[9] = guid.Data4[1];
data[10] = guid.Data4[2];
data[11] = guid.Data4[3];
data[12] = guid.Data4[4];
data[13] = guid.Data4[5];
data[14] = guid.Data4[6];
data[15] = guid.Data4[7];
dsc result;
result.makeText(16, ttype_binary, data);
@ -6277,15 +6272,16 @@ dsc* evlUuidToChar(thread_db* tdbb, const SysFunction* function, const NestValue
Arg::Str(function->name));
}
char buffer[GUID_BUFF_SIZE];
sprintf(buffer, GUID_NEW_FORMAT,
USHORT(data[0]), USHORT(data[1]), USHORT(data[2]), USHORT(data[3]), USHORT(data[4]),
USHORT(data[5]), USHORT(data[6]), USHORT(data[7]), USHORT(data[8]), USHORT(data[9]),
USHORT(data[10]), USHORT(data[11]), USHORT(data[12]), USHORT(data[13]), USHORT(data[14]),
USHORT(data[15]));
UCHAR buffer[GUID_BUFF_SIZE];
sprintf(reinterpret_cast<char*>(buffer),
"%02hhX%02hhX%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
data[0], data[1], data[2], data[3], data[4],
data[5], data[6], data[7], data[8], data[9],
data[10], data[11], data[12], data[13], data[14],
data[15]);
dsc result;
result.makeText(GUID_BODY_SIZE, ttype_ascii, reinterpret_cast<UCHAR*>(buffer) + 1);
result.makeText(GUID_BODY_SIZE, ttype_ascii, buffer);
EVL_make_value(tdbb, &result, impure);
return &impure->vlu_desc;

View File

@ -97,6 +97,7 @@ Config::Config()
logArchiveTimeout(DEFAULT_LOG_ARCHIVE_TIMEOUT),
syncReplicas(getPool()),
logSourceDirectory(getPool()),
sourceGuid{},
verboseLogging(false),
applyIdleTimeout(DEFAULT_APPLY_IDLE_TIMEOUT),
applyErrorTimeout(DEFAULT_APPLY_ERROR_TIMEOUT),
@ -105,7 +106,6 @@ Config::Config()
reportErrors(false),
disableOnError(true)
{
sourceGuid.alignment = 0;
}
Config::Config(const Config& other)
@ -123,6 +123,7 @@ Config::Config(const Config& other)
logArchiveTimeout(other.logArchiveTimeout),
syncReplicas(getPool(), other.syncReplicas),
logSourceDirectory(getPool(), other.logSourceDirectory),
sourceGuid{},
verboseLogging(other.verboseLogging),
applyIdleTimeout(other.applyIdleTimeout),
applyErrorTimeout(other.applyErrorTimeout),
@ -131,7 +132,6 @@ Config::Config(const Config& other)
reportErrors(other.reportErrors),
disableOnError(other.disableOnError)
{
sourceGuid.alignment = 0;
}
// This routine is used to match the database on the master side.

View File

@ -350,7 +350,7 @@ namespace
bool checkGuid(const Guid& guid)
{
if (!m_config->sourceGuid.alignment)
if (!m_config->sourceGuid.Data1)
return true;
if (!memcmp(&guid, &m_config->sourceGuid, sizeof(Guid)))