diff --git a/headers/build/private/shared/Uuid.h b/headers/build/private/shared/Uuid.h new file mode 100644 index 0000000000..2541993c85 --- /dev/null +++ b/headers/build/private/shared/Uuid.h @@ -0,0 +1 @@ +#include <../private/shared/Uuid.h> diff --git a/headers/private/shared/Uuid.h b/headers/private/shared/Uuid.h new file mode 100644 index 0000000000..5e52072f61 --- /dev/null +++ b/headers/private/shared/Uuid.h @@ -0,0 +1,96 @@ +/* + * Copyright 2013, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _UUID_H_ +#define _UUID_H_ + + +#include + + +namespace BPrivate { + + +class BUuid { +public: + BUuid(); + BUuid(const BUuid& other); + ~BUuid(); + + bool IsNil() const; + + BUuid& SetToRandom(); + + BString ToString() const; + + int Compare(const BUuid& other) const; + + inline bool operator==(const BUuid& other) const; + inline bool operator!=(const BUuid& other) const; + + inline bool operator<(const BUuid& other) const; + inline bool operator>(const BUuid& other) const; + inline bool operator<=(const BUuid& other) const; + inline bool operator>=(const BUuid& other) const; + + BUuid& operator=(const BUuid& other); + +private: + bool _SetToDevRandom(); + void _SetToRandomFallback(); + +private: + uint8 fValue[16]; +}; + + +inline bool +BUuid::operator==(const BUuid& other) const +{ + return Compare(other) == 0; +} + + +inline bool +BUuid::operator!=(const BUuid& other) const +{ + return Compare(other) != 0; +} + + +inline bool +BUuid::operator<(const BUuid& other) const +{ + return Compare(other) < 0; +} + + +inline bool +BUuid::operator>(const BUuid& other) const +{ + return Compare(other) > 0; +} + + +inline bool +BUuid::operator<=(const BUuid& other) const +{ + return Compare(other) <= 0; +} + + +inline bool +BUuid::operator>=(const BUuid& other) const +{ + return Compare(other) >= 0; +} + + +} // namespace BPrivate + + +using BPrivate::BUuid; + + +#endif // _UUID_H_ diff --git a/src/kits/shared/Jamfile b/src/kits/shared/Jamfile index 2459568ac7..d4aca5381d 100644 --- a/src/kits/shared/Jamfile +++ b/src/kits/shared/Jamfile @@ -33,6 +33,7 @@ StaticLibrary libshared.a : ShakeTrackingFilter.cpp StringForRate.cpp StringForSize.cpp + Uuid.cpp Variant.cpp ; diff --git a/src/kits/shared/Uuid.cpp b/src/kits/shared/Uuid.cpp new file mode 100644 index 0000000000..23fd3c70b6 --- /dev/null +++ b/src/kits/shared/Uuid.cpp @@ -0,0 +1,160 @@ +/* + * Copyright 2013, Haiku, Inc. + * 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;