| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 | // Copyright (C) 2013 by Maxim Bublis <[email protected]>//// Permission is hereby granted, free of charge, to any person obtaining// a copy of this software and associated documentation files (the// "Software"), to deal in the Software without restriction, including// without limitation the rights to use, copy, modify, merge, publish,// distribute, sublicense, and/or sell copies of the Software, and to// permit persons to whom the Software is furnished to do so, subject to// the following conditions://// The above copyright notice and this permission notice shall be// included in all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.// Package uuid provides implementation of Universally Unique Identifier (UUID).// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and// version 2 (as specified in DCE 1.1).package uuidimport (	"bytes"	"crypto/md5"	"crypto/rand"	"crypto/sha1"	"encoding/binary"	"encoding/hex"	"fmt"	"hash"	"net"	"os"	"strings"	"sync"	"time")// UUID layout variants.const (	VariantNCS = iota	VariantRFC4122	VariantMicrosoft	VariantFuture)// UUID DCE domains.const (	DomainPerson = iota	DomainGroup	DomainOrg)// Difference in 100-nanosecond intervals between// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).const epochStart = 122192928000000000// UUID v1/v2 storage.var (	storageMutex  sync.Mutex	clockSequence uint16	lastTime      uint64	hardwareAddr  [6]byte	posixUID      = uint32(os.Getuid())	posixGID      = uint32(os.Getgid()))// Epoch calculation functionvar epochFunc func() uint64// Initialize storagefunc init() {	buf := make([]byte, 2)	rand.Read(buf)	clockSequence = binary.BigEndian.Uint16(buf)	// Initialize hardwareAddr randomly in case	// of real network interfaces absence	rand.Read(hardwareAddr[:])	// Set multicast bit as recommended in RFC 4122	hardwareAddr[0] |= 0x01	interfaces, err := net.Interfaces()	if err == nil {		for _, iface := range interfaces {			if len(iface.HardwareAddr) >= 6 {				copy(hardwareAddr[:], iface.HardwareAddr)				break			}		}	}	epochFunc = unixTimeFunc}// Returns difference in 100-nanosecond intervals between// UUID epoch (October 15, 1582) and current time.// This is default epoch calculation function.func unixTimeFunc() uint64 {	return epochStart + uint64(time.Now().UnixNano()/100)}// UUID representation compliant with specification// described in RFC 4122.type UUID [16]byte// Predefined namespace UUIDs.var (	NamespaceDNS, _  = FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")	NamespaceURL, _  = FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")	NamespaceOID, _  = FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")	NamespaceX500, _ = FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))// And returns result of binary AND of two UUIDs.func And(u1 UUID, u2 UUID) UUID {	u := UUID{}	for i := 0; i < 16; i++ {		u[i] = u1[i] & u2[i]	}	return u}// Or returns result of binary OR of two UUIDs.func Or(u1 UUID, u2 UUID) UUID {	u := UUID{}	for i := 0; i < 16; i++ {		u[i] = u1[i] | u2[i]	}	return u}// Equal returns true if u1 and u2 equals, otherwise returns false.func Equal(u1 UUID, u2 UUID) bool {	return bytes.Equal(u1[:], u2[:])}// Version returns algorithm version used to generate UUID.func (u UUID) Version() uint {	return uint(u[6] >> 4)}// Variant returns UUID layout variant.func (u UUID) Variant() uint {	switch {	case (u[8] & 0x80) == 0x00:		return VariantNCS	case (u[8]&0xc0)|0x80 == 0x80:		return VariantRFC4122	case (u[8]&0xe0)|0xc0 == 0xc0:		return VariantMicrosoft	}	return VariantFuture}// Bytes returns bytes slice representation of UUID.func (u UUID) Bytes() []byte {	return u[:]}// Returns canonical string representation of UUID:// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.func (u UUID) String() string {	return fmt.Sprintf("%x-%x-%x-%x-%x",		u[:4], u[4:6], u[6:8], u[8:10], u[10:])}// SetVersion sets version bits.func (u *UUID) SetVersion(v byte) {	u[6] = (u[6] & 0x0f) | (v << 4)}// SetVariant sets variant bits as described in RFC 4122.func (u *UUID) SetVariant() {	u[8] = (u[8] & 0xbf) | 0x80}// MarshalText implements the encoding.TextMarshaler interface.// The encoding is the same as returned by String.func (u UUID) MarshalText() (text []byte, err error) {	text = []byte(u.String())	return}// UnmarshalText implements the encoding.TextUnmarshaler interface.// UUID is expected in a form accepted by FromString.func (u *UUID) UnmarshalText(text []byte) error {	s := string(text)	u2, err := FromString(s)	if err != nil {		return err	}	*u = u2	return nil}// MarshalBinary implements the encoding.BinaryMarshaler interface.func (u UUID) MarshalBinary() (data []byte, err error) {	data = u.Bytes()	return}// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.func (u *UUID) UnmarshalBinary(data []byte) error {	u2, err := FromBytes(data)	if err != nil {		return err	}	*u = u2	return nil}// FromBytes returns UUID converted from raw byte slice input.// It will return error if the slice isn't 16 bytes long.func FromBytes(input []byte) (u UUID, err error) {	if len(input) != 16 {		err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(input))		return	}	copy(u[:], input)	return}// FromString returns UUID parsed from string input.// Following formats are supported:// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"func FromString(input string) (u UUID, err error) {	s := strings.Replace(input, "-", "", -1)	if len(s) == 41 && s[:9] == "urn:uuid:" {		s = s[9:]	} else if len(s) == 34 && s[0] == '{' && s[33] == '}' {		s = s[1:33]	}	if len(s) != 32 {		err = fmt.Errorf("uuid: invalid UUID string: %s", input)		return	}	b := []byte(s)	_, err = hex.Decode(u[:], b)	return}// Returns UUID v1/v2 storage state.// Returns epoch timestamp and clock sequence.func getStorage() (uint64, uint16) {	storageMutex.Lock()	defer storageMutex.Unlock()	timeNow := epochFunc()	// Clock changed backwards since last UUID generation.	// Should increase clock sequence.	if timeNow <= lastTime {		clockSequence++	}	lastTime = timeNow	return timeNow, clockSequence}// NewV1 returns UUID based on current timestamp and MAC address.func NewV1() UUID {	u := UUID{}	timeNow, clockSeq := getStorage()	binary.BigEndian.PutUint32(u[0:], uint32(timeNow))	binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))	binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))	binary.BigEndian.PutUint16(u[8:], clockSeq)	copy(u[10:], hardwareAddr[:])	u.SetVersion(1)	u.SetVariant()	return u}// NewV2 returns DCE Security UUID based on POSIX UID/GID.func NewV2(domain byte) UUID {	u := UUID{}	switch domain {	case DomainPerson:		binary.BigEndian.PutUint32(u[0:], posixUID)	case DomainGroup:		binary.BigEndian.PutUint32(u[0:], posixGID)	}	timeNow, clockSeq := getStorage()	binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))	binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))	binary.BigEndian.PutUint16(u[8:], clockSeq)	u[9] = domain	copy(u[10:], hardwareAddr[:])	u.SetVersion(2)	u.SetVariant()	return u}// NewV3 returns UUID based on MD5 hash of namespace UUID and name.func NewV3(ns UUID, name string) UUID {	u := newFromHash(md5.New(), ns, name)	u.SetVersion(3)	u.SetVariant()	return u}// NewV4 returns random generated UUID.func NewV4() UUID {	u := UUID{}	rand.Read(u[:])	u.SetVersion(4)	u.SetVariant()	return u}// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.func NewV5(ns UUID, name string) UUID {	u := newFromHash(sha1.New(), ns, name)	u.SetVersion(5)	u.SetVariant()	return u}// Returns UUID based on hashing of namespace UUID and name.func newFromHash(h hash.Hash, ns UUID, name string) UUID {	u := UUID{}	h.Write(ns[:])	h.Write([]byte(name))	copy(u[:], h.Sum(nil))	return u}
 |