/* * Copyright 2013 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. */ #include #include #include #include #include #include static const char* const kHexChars = "0123456789abcdef"; static const size_t kVersionByteIndex = 6; static const size_t kVariantByteIndex = 8; static bool init_random_seed() { // set a time-based seed timespec time; clock_gettime(CLOCK_REALTIME, &time); uint32 seed = (uint32)time.tv_sec ^ (uint32)time.tv_nsec; // factor in a stack address -- with address space layout randomization // that adds a bit of additional randomness seed ^= (uint32)(addr_t)&time; srandom(seed); return true; } namespace BPrivate { BUuid::BUuid() { memset(fValue, 0, sizeof(fValue)); } BUuid::BUuid(const BUuid& other) { memcpy(fValue, other.fValue, sizeof(fValue)); } BUuid::~BUuid() { } bool BUuid::IsNil() const { for (size_t i = 0; i < sizeof(fValue); i++) { if (fValue[i] != 0) return false; } return true; } BUuid& BUuid::SetToRandom() { if (!BUuid::_SetToDevRandom()) BUuid::_SetToRandomFallback(); // set variant and version fValue[kVariantByteIndex] &= 0x3f; fValue[kVariantByteIndex] |= 0x80; fValue[kVersionByteIndex] &= 0x0f; fValue[kVersionByteIndex] |= 4 << 4; // version 4 return *this; } BString BUuid::ToString() const { char buffer[32]; for (size_t i = 0; i < 16; i++) { buffer[2 * i] = kHexChars[fValue[i] >> 4]; buffer[2 * i + 1] = kHexChars[fValue[i] & 0xf]; } return BString().SetToFormat("%.8s-%.4s-%.4s-%.4s-%.12s", buffer, buffer + 8, buffer + 12, buffer + 16, buffer + 20); } int BUuid::Compare(const BUuid& other) const { return memcmp(fValue, other.fValue, sizeof(fValue)); } BUuid& BUuid::operator=(const BUuid& other) { memcpy(fValue, other.fValue, sizeof(fValue)); return *this; } bool BUuid::_SetToDevRandom() { // open device int fd = open("/dev/urandom", O_RDONLY); if (fd < 0) { fd = open("/dev/random", O_RDONLY); if (fd < 0) return false; } // read bytes ssize_t bytesRead = read(fd, fValue, sizeof(fValue)); close(fd); return bytesRead == (ssize_t)sizeof(fValue); } void BUuid::_SetToRandomFallback() { static bool sSeedInitialized = init_random_seed(); (void)sSeedInitialized; for (int32 i = 0; i < 4; i++) { uint32 value = random(); fValue[4 * i + 0] = uint8(value >> 24); fValue[4 * i + 1] = uint8(value >> 16); fValue[4 * i + 2] = uint8(value >> 8); fValue[4 * i + 3] = uint8(value); } // random() returns 31 bit numbers only, so we move a few bits from where // we overwrite them with the version anyway. uint8 bitsToMove = fValue[kVersionByteIndex]; for (int32 i = 0; i < 4; i++) fValue[4 * i] |= (bitsToMove << i) & 0x80; } } // namespace BPrivate using BPrivate::BUuid;