@ -0,0 +1,27 @@ | |||
Copyright (c) 2009,2014 Google Inc. All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are | |||
met: | |||
* Redistributions of source code must retain the above copyright | |||
notice, this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above | |||
copyright notice, this list of conditions and the following disclaimer | |||
in the documentation and/or other materials provided with the | |||
distribution. | |||
* Neither the name of Google Inc. nor the names of its | |||
contributors may be used to endorse or promote products derived from | |||
this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,84 @@ | |||
// Copyright 2011 Google Inc. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package uuid | |||
import ( | |||
"encoding/binary" | |||
"fmt" | |||
"os" | |||
) | |||
// A Domain represents a Version 2 domain | |||
type Domain byte | |||
// Domain constants for DCE Security (Version 2) UUIDs. | |||
const ( | |||
Person = Domain(0) | |||
Group = Domain(1) | |||
Org = Domain(2) | |||
) | |||
// NewDCESecurity returns a DCE Security (Version 2) UUID. | |||
// | |||
// The domain should be one of Person, Group or Org. | |||
// On a POSIX system the id should be the users UID for the Person | |||
// domain and the users GID for the Group. The meaning of id for | |||
// the domain Org or on non-POSIX systems is site defined. | |||
// | |||
// For a given domain/id pair the same token may be returned for up to | |||
// 7 minutes and 10 seconds. | |||
func NewDCESecurity(domain Domain, id uint32) UUID { | |||
uuid := NewUUID() | |||
if uuid != nil { | |||
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 | |||
uuid[9] = byte(domain) | |||
binary.BigEndian.PutUint32(uuid[0:], id) | |||
} | |||
return uuid | |||
} | |||
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person | |||
// domain with the id returned by os.Getuid. | |||
// | |||
// NewDCEPerson(Person, uint32(os.Getuid())) | |||
func NewDCEPerson() UUID { | |||
return NewDCESecurity(Person, uint32(os.Getuid())) | |||
} | |||
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group | |||
// domain with the id returned by os.Getgid. | |||
// | |||
// NewDCEGroup(Group, uint32(os.Getgid())) | |||
func NewDCEGroup() UUID { | |||
return NewDCESecurity(Group, uint32(os.Getgid())) | |||
} | |||
// Domain returns the domain for a Version 2 UUID or false. | |||
func (uuid UUID) Domain() (Domain, bool) { | |||
if v, _ := uuid.Version(); v != 2 { | |||
return 0, false | |||
} | |||
return Domain(uuid[9]), true | |||
} | |||
// Id returns the id for a Version 2 UUID or false. | |||
func (uuid UUID) Id() (uint32, bool) { | |||
if v, _ := uuid.Version(); v != 2 { | |||
return 0, false | |||
} | |||
return binary.BigEndian.Uint32(uuid[0:4]), true | |||
} | |||
func (d Domain) String() string { | |||
switch d { | |||
case Person: | |||
return "Person" | |||
case Group: | |||
return "Group" | |||
case Org: | |||
return "Org" | |||
} | |||
return fmt.Sprintf("Domain%d", int(d)) | |||
} |
@ -0,0 +1,8 @@ | |||
// Copyright 2011 Google Inc. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// The uuid package generates and inspects UUIDs. | |||
// | |||
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security Services. | |||
package uuid |
@ -0,0 +1,53 @@ | |||
// Copyright 2011 Google Inc. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package uuid | |||
import ( | |||
"crypto/md5" | |||
"crypto/sha1" | |||
"hash" | |||
) | |||
// Well known Name Space IDs and UUIDs | |||
var ( | |||
NameSpace_DNS = Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") | |||
NameSpace_URL = Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8") | |||
NameSpace_OID = Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8") | |||
NameSpace_X500 = Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8") | |||
NIL = Parse("00000000-0000-0000-0000-000000000000") | |||
) | |||
// NewHash returns a new UUID dervied from the hash of space concatenated with | |||
// data generated by h. The hash should be at least 16 byte in length. The | |||
// first 16 bytes of the hash are used to form the UUID. The version of the | |||
// UUID will be the lower 4 bits of version. NewHash is used to implement | |||
// NewMD5 and NewSHA1. | |||
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { | |||
h.Reset() | |||
h.Write(space) | |||
h.Write([]byte(data)) | |||
s := h.Sum(nil) | |||
uuid := make([]byte, 16) | |||
copy(uuid, s) | |||
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) | |||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant | |||
return uuid | |||
} | |||
// NewMD5 returns a new MD5 (Version 3) UUID based on the | |||
// supplied name space and data. | |||
// | |||
// NewHash(md5.New(), space, data, 3) | |||
func NewMD5(space UUID, data []byte) UUID { | |||
return NewHash(md5.New(), space, data, 3) | |||
} | |||
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the | |||
// supplied name space and data. | |||
// | |||
// NewHash(sha1.New(), space, data, 5) | |||
func NewSHA1(space UUID, data []byte) UUID { | |||
return NewHash(sha1.New(), space, data, 5) | |||
} |
@ -0,0 +1,30 @@ | |||
// Copyright 2014 Google Inc. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package uuid | |||
import "errors" | |||
func (u UUID) MarshalJSON() ([]byte, error) { | |||
if len(u) == 0 { | |||
return []byte(`""`), nil | |||
} | |||
return []byte(`"` + u.String() + `"`), nil | |||
} | |||
func (u *UUID) UnmarshalJSON(data []byte) error { | |||
if len(data) == 0 || string(data) == `""` { | |||
return nil | |||
} | |||
if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' { | |||
return errors.New("invalid UUID format") | |||
} | |||
data = data[1 : len(data)-1] | |||
uu := Parse(string(data)) | |||
if uu == nil { | |||
return errors.New("invalid UUID format") | |||
} | |||
*u = uu | |||
return nil | |||
} |
@ -0,0 +1,32 @@ | |||
// Copyright 2014 Google Inc. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package uuid | |||
import ( | |||
"encoding/json" | |||
"reflect" | |||
"testing" | |||
) | |||
var testUUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") | |||
func TestJSON(t *testing.T) { | |||
type S struct { | |||
ID1 UUID | |||
ID2 UUID | |||
} | |||
s1 := S{ID1: testUUID} | |||
data, err := json.Marshal(&s1) | |||
if err != nil { | |||
t.Fatal(err) | |||
} | |||
var s2 S | |||
if err := json.Unmarshal(data, &s2); err != nil { | |||
t.Fatal(err) | |||
} | |||
if !reflect.DeepEqual(&s1, &s2) { | |||
t.Errorf("got %#v, want %#v", s2, s1) | |||
} | |||
} |
@ -0,0 +1,101 @@ | |||
// Copyright 2011 Google Inc. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package uuid | |||
import "net" | |||
var ( | |||
interfaces []net.Interface // cached list of interfaces | |||
ifname string // name of interface being used | |||
nodeID []byte // hardware for version 1 UUIDs | |||
) | |||
// NodeInterface returns the name of the interface from which the NodeID was | |||
// derived. The interface "user" is returned if the NodeID was set by | |||
// SetNodeID. | |||
func NodeInterface() string { | |||
return ifname | |||
} | |||
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. | |||
// If name is "" then the first usable interface found will be used or a random | |||
// Node ID will be generated. If a named interface cannot be found then false | |||
// is returned. | |||
// | |||
// SetNodeInterface never fails when name is "". | |||
func SetNodeInterface(name string) bool { | |||
if interfaces == nil { | |||
var err error | |||
interfaces, err = net.Interfaces() | |||
if err != nil && name != "" { | |||
return false | |||
} | |||
} | |||
for _, ifs := range interfaces { | |||
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { | |||
if setNodeID(ifs.HardwareAddr) { | |||
ifname = ifs.Name | |||
return true | |||
} | |||
} | |||
} | |||
// We found no interfaces with a valid hardware address. If name | |||
// does not specify a specific interface generate a random Node ID | |||
// (section 4.1.6) | |||
if name == "" { | |||
if nodeID == nil { | |||
nodeID = make([]byte, 6) | |||
} | |||
randomBits(nodeID) | |||
return true | |||
} | |||
return false | |||
} | |||
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID | |||
// if not already set. | |||
func NodeID() []byte { | |||
if nodeID == nil { | |||
SetNodeInterface("") | |||
} | |||
nid := make([]byte, 6) | |||
copy(nid, nodeID) | |||
return nid | |||
} | |||
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes | |||
// of id are used. If id is less than 6 bytes then false is returned and the | |||
// Node ID is not set. | |||
func SetNodeID(id []byte) bool { | |||
if setNodeID(id) { | |||
ifname = "user" | |||
return true | |||
} | |||
return false | |||
} | |||
func setNodeID(id []byte) bool { | |||
if len(id) < 6 { | |||
return false | |||
} | |||
if nodeID == nil { | |||
nodeID = make([]byte, 6) | |||
} | |||
copy(nodeID, id) | |||
return true | |||
} | |||
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is | |||
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs. | |||
func (uuid UUID) NodeID() []byte { | |||
if len(uuid) != 16 { | |||
return nil | |||
} | |||
node := make([]byte, 6) | |||
copy(node, uuid[10:]) | |||
return node | |||
} |
@ -0,0 +1,66 @@ | |||
// Copyright 2014 Google Inc. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package uuid | |||
import ( | |||
"flag" | |||
"runtime" | |||
"testing" | |||
"time" | |||
) | |||
// This test is only run when --regressions is passed on the go test line. | |||
var regressions = flag.Bool("regressions", false, "run uuid regression tests") | |||
// TestClockSeqRace tests for a particular race condition of returning two | |||
// identical Version1 UUIDs. The duration of 1 minute was chosen as the race | |||
// condition, before being fixed, nearly always occured in under 30 seconds. | |||
func TestClockSeqRace(t *testing.T) { | |||
if !*regressions { | |||
t.Skip("skipping regression tests") | |||
} | |||
duration := time.Minute | |||
done := make(chan struct{}) | |||
defer close(done) | |||
ch := make(chan UUID, 10000) | |||
ncpu := runtime.NumCPU() | |||
switch ncpu { | |||
case 0, 1: | |||
// We can't run the test effectively. | |||
t.Skip("skipping race test, only one CPU detected") | |||
return | |||
default: | |||
runtime.GOMAXPROCS(ncpu) | |||
} | |||
for i := 0; i < ncpu; i++ { | |||
go func() { | |||
for { | |||
select { | |||
case <-done: | |||
return | |||
case ch <- NewUUID(): | |||
} | |||
} | |||
}() | |||
} | |||
uuids := make(map[string]bool) | |||
cnt := 0 | |||
start := time.Now() | |||
for u := range ch { | |||
s := u.String() | |||
if uuids[s] { | |||
t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s) | |||
return | |||
} | |||
uuids[s] = true | |||
if time.Since(start) > duration { | |||
return | |||
} | |||
cnt++ | |||
} | |||
} |
@ -0,0 +1,132 @@ | |||
// Copyright 2014 Google Inc. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package uuid | |||
import ( | |||
"encoding/binary" | |||
"sync" | |||
"time" | |||
) | |||
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct | |||
// 1582. | |||
type Time int64 | |||
const ( | |||
lillian = 2299160 // Julian day of 15 Oct 1582 | |||
unix = 2440587 // Julian day of 1 Jan 1970 | |||
epoch = unix - lillian // Days between epochs | |||
g1582 = epoch * 86400 // seconds between epochs | |||
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs | |||
) | |||
var ( | |||
mu sync.Mutex | |||
lasttime uint64 // last time we returned | |||
clock_seq uint16 // clock sequence for this run | |||
timeNow = time.Now // for testing | |||
) | |||
// UnixTime converts t the number of seconds and nanoseconds using the Unix | |||
// epoch of 1 Jan 1970. | |||
func (t Time) UnixTime() (sec, nsec int64) { | |||
sec = int64(t - g1582ns100) | |||
nsec = (sec % 10000000) * 100 | |||
sec /= 10000000 | |||
return sec, nsec | |||
} | |||
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and | |||
// clock sequence as well as adjusting the clock sequence as needed. An error | |||
// is returned if the current time cannot be determined. | |||
func GetTime() (Time, uint16, error) { | |||
defer mu.Unlock() | |||
mu.Lock() | |||
return getTime() | |||
} | |||
func getTime() (Time, uint16, error) { | |||
t := timeNow() | |||
// If we don't have a clock sequence already, set one. | |||
if clock_seq == 0 { | |||
setClockSequence(-1) | |||
} | |||
now := uint64(t.UnixNano()/100) + g1582ns100 | |||
// If time has gone backwards with this clock sequence then we | |||
// increment the clock sequence | |||
if now <= lasttime { | |||
clock_seq = ((clock_seq + 1) & 0x3fff) | 0x8000 | |||
} | |||
lasttime = now | |||
return Time(now), clock_seq, nil | |||
} | |||
// ClockSequence returns the current clock sequence, generating one if not | |||
// already set. The clock sequence is only used for Version 1 UUIDs. | |||
// | |||
// The uuid package does not use global static storage for the clock sequence or | |||
// the last time a UUID was generated. Unless SetClockSequence a new random | |||
// clock sequence is generated the first time a clock sequence is requested by | |||
// ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated | |||
// for | |||
func ClockSequence() int { | |||
defer mu.Unlock() | |||
mu.Lock() | |||
return clockSequence() | |||
} | |||
func clockSequence() int { | |||
if clock_seq == 0 { | |||
setClockSequence(-1) | |||
} | |||
return int(clock_seq & 0x3fff) | |||
} | |||
// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to | |||
// -1 causes a new sequence to be generated. | |||
func SetClockSequence(seq int) { | |||
defer mu.Unlock() | |||
mu.Lock() | |||
setClockSequence(seq) | |||
} | |||
func setClockSequence(seq int) { | |||
if seq == -1 { | |||
var b [2]byte | |||
randomBits(b[:]) // clock sequence | |||
seq = int(b[0])<<8 | int(b[1]) | |||
} | |||
old_seq := clock_seq | |||
clock_seq = uint16(seq&0x3fff) | 0x8000 // Set our variant | |||
if old_seq != clock_seq { | |||
lasttime = 0 | |||
} | |||
} | |||
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in | |||
// uuid. It returns false if uuid is not valid. The time is only well defined | |||
// for version 1 and 2 UUIDs. | |||
func (uuid UUID) Time() (Time, bool) { | |||
if len(uuid) != 16 { | |||
return 0, false | |||
} | |||
time := int64(binary.BigEndian.Uint32(uuid[0:4])) | |||
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 | |||
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 | |||
return Time(time), true | |||
} | |||
// ClockSequence returns the clock sequence encoded in uuid. It returns false | |||
// if uuid is not valid. The clock sequence is only well defined for version 1 | |||
// and 2 UUIDs. | |||
func (uuid UUID) ClockSequence() (int, bool) { | |||
if len(uuid) != 16 { | |||
return 0, false | |||
} | |||
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff, true | |||
} |
@ -0,0 +1,43 @@ | |||
// Copyright 2011 Google Inc. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package uuid | |||
import ( | |||
"io" | |||
) | |||
// randomBits completely fills slice b with random data. | |||
func randomBits(b []byte) { | |||
if _, err := io.ReadFull(rander, b); err != nil { | |||
panic(err.Error()) // rand should never fail | |||
} | |||
} | |||
// xvalues returns the value of a byte as a hexadecimal digit or 255. | |||
var xvalues = []byte{ | |||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, | |||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | |||
} | |||
// xtob converts the the first two hex bytes of x into a byte. | |||
func xtob(x string) (byte, bool) { | |||
b1 := xvalues[x[0]] | |||
b2 := xvalues[x[1]] | |||
return (b1 << 4) | b2, b1 != 255 && b2 != 255 | |||
} |
@ -0,0 +1,163 @@ | |||
// Copyright 2011 Google Inc. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package uuid | |||
import ( | |||
"bytes" | |||
"crypto/rand" | |||
"fmt" | |||
"io" | |||
"strings" | |||
) | |||
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC | |||
// 4122. | |||
type UUID []byte | |||
// A Version represents a UUIDs version. | |||
type Version byte | |||
// A Variant represents a UUIDs variant. | |||
type Variant byte | |||
// Constants returned by Variant. | |||
const ( | |||
Invalid = Variant(iota) // Invalid UUID | |||
RFC4122 // The variant specified in RFC4122 | |||
Reserved // Reserved, NCS backward compatibility. | |||
Microsoft // Reserved, Microsoft Corporation backward compatibility. | |||
Future // Reserved for future definition. | |||
) | |||
var rander = rand.Reader // random function | |||
// New returns a new random (version 4) UUID as a string. It is a convenience | |||
// function for NewRandom().String(). | |||
func New() string { | |||
return NewRandom().String() | |||
} | |||
// Parse decodes s into a UUID or returns nil. Both the UUID form of | |||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and | |||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded. | |||
func Parse(s string) UUID { | |||
if len(s) == 36+9 { | |||
if strings.ToLower(s[:9]) != "urn:uuid:" { | |||
return nil | |||
} | |||
s = s[9:] | |||
} else if len(s) != 36 { | |||
return nil | |||
} | |||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { | |||
return nil | |||
} | |||
uuid := make([]byte, 16) | |||
for i, x := range []int{ | |||
0, 2, 4, 6, | |||
9, 11, | |||
14, 16, | |||
19, 21, | |||
24, 26, 28, 30, 32, 34} { | |||
if v, ok := xtob(s[x:]); !ok { | |||
return nil | |||
} else { | |||
uuid[i] = v | |||
} | |||
} | |||
return uuid | |||
} | |||
// Equal returns true if uuid1 and uuid2 are equal. | |||
func Equal(uuid1, uuid2 UUID) bool { | |||
return bytes.Equal(uuid1, uuid2) | |||
} | |||
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | |||
// , or "" if uuid is invalid. | |||
func (uuid UUID) String() string { | |||
if uuid == nil || len(uuid) != 16 { | |||
return "" | |||
} | |||
b := []byte(uuid) | |||
return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", | |||
b[:4], b[4:6], b[6:8], b[8:10], b[10:]) | |||
} | |||
// URN returns the RFC 2141 URN form of uuid, | |||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. | |||
func (uuid UUID) URN() string { | |||
if uuid == nil || len(uuid) != 16 { | |||
return "" | |||
} | |||
b := []byte(uuid) | |||
return fmt.Sprintf("urn:uuid:%08x-%04x-%04x-%04x-%012x", | |||
b[:4], b[4:6], b[6:8], b[8:10], b[10:]) | |||
} | |||
// Variant returns the variant encoded in uuid. It returns Invalid if | |||
// uuid is invalid. | |||
func (uuid UUID) Variant() Variant { | |||
if len(uuid) != 16 { | |||
return Invalid | |||
} | |||
switch { | |||
case (uuid[8] & 0xc0) == 0x80: | |||
return RFC4122 | |||
case (uuid[8] & 0xe0) == 0xc0: | |||
return Microsoft | |||
case (uuid[8] & 0xe0) == 0xe0: | |||
return Future | |||
default: | |||
return Reserved | |||
} | |||
panic("unreachable") | |||
} | |||
// Version returns the verison of uuid. It returns false if uuid is not | |||
// valid. | |||
func (uuid UUID) Version() (Version, bool) { | |||
if len(uuid) != 16 { | |||
return 0, false | |||
} | |||
return Version(uuid[6] >> 4), true | |||
} | |||
func (v Version) String() string { | |||
if v > 15 { | |||
return fmt.Sprintf("BAD_VERSION_%d", v) | |||
} | |||
return fmt.Sprintf("VERSION_%d", v) | |||
} | |||
func (v Variant) String() string { | |||
switch v { | |||
case RFC4122: | |||
return "RFC4122" | |||
case Reserved: | |||
return "Reserved" | |||
case Microsoft: | |||
return "Microsoft" | |||
case Future: | |||
return "Future" | |||
case Invalid: | |||
return "Invalid" | |||
} | |||
return fmt.Sprintf("BadVariant%d", int(v)) | |||
} | |||
// SetRand sets the random number generator to r, which implents io.Reader. | |||
// If r.Read returns an error when the package requests random data then | |||
// a panic will be issued. | |||
// | |||
// Calling SetRand with nil sets the random number generator to the default | |||
// generator. | |||
func SetRand(r io.Reader) { | |||
if r == nil { | |||
rander = rand.Reader | |||
return | |||
} | |||
rander = r | |||
} |
@ -0,0 +1,390 @@ | |||
// Copyright 2011 Google Inc. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package uuid | |||
import ( | |||
"bytes" | |||
"fmt" | |||
"os" | |||
"strings" | |||
"testing" | |||
"time" | |||
) | |||
type test struct { | |||
in string | |||
version Version | |||
variant Variant | |||
isuuid bool | |||
} | |||
var tests = []test{ | |||
{"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true}, | |||
{"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true}, | |||
{"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true}, | |||
{"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true}, | |||
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, | |||
{"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true}, | |||
{"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true}, | |||
{"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true}, | |||
{"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true}, | |||
{"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true}, | |||
{"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true}, | |||
{"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true}, | |||
{"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true}, | |||
{"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true}, | |||
{"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true}, | |||
{"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true}, | |||
{"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, | |||
{"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, | |||
{"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, | |||
{"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true}, | |||
{"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true}, | |||
{"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true}, | |||
{"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true}, | |||
{"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true}, | |||
{"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true}, | |||
{"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true}, | |||
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, | |||
{"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true}, | |||
{"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true}, | |||
{"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true}, | |||
{"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true}, | |||
{"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true}, | |||
{"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true}, | |||
{"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true}, | |||
{"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false}, | |||
{"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false}, | |||
{"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false}, | |||
{"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false}, | |||
{"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false}, | |||
{"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false}, | |||
} | |||
var constants = []struct { | |||
c interface{} | |||
name string | |||
}{ | |||
{Person, "Person"}, | |||
{Group, "Group"}, | |||
{Org, "Org"}, | |||
{Invalid, "Invalid"}, | |||
{RFC4122, "RFC4122"}, | |||
{Reserved, "Reserved"}, | |||
{Microsoft, "Microsoft"}, | |||
{Future, "Future"}, | |||
{Domain(17), "Domain17"}, | |||
{Variant(42), "BadVariant42"}, | |||
} | |||
func testTest(t *testing.T, in string, tt test) { | |||
uuid := Parse(in) | |||
if ok := (uuid != nil); ok != tt.isuuid { | |||
t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid) | |||
} | |||
if uuid == nil { | |||
return | |||
} | |||
if v := uuid.Variant(); v != tt.variant { | |||
t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant) | |||
} | |||
if v, _ := uuid.Version(); v != tt.version { | |||
t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version) | |||
} | |||
} | |||
func TestUUID(t *testing.T) { | |||
for _, tt := range tests { | |||
testTest(t, tt.in, tt) | |||
testTest(t, strings.ToUpper(tt.in), tt) | |||
} | |||
} | |||
func TestConstants(t *testing.T) { | |||
for x, tt := range constants { | |||
v, ok := tt.c.(fmt.Stringer) | |||
if !ok { | |||
t.Errorf("%x: %v: not a stringer", x, v) | |||
} else if s := v.String(); s != tt.name { | |||
v, _ := tt.c.(int) | |||
t.Errorf("%x: Constant %T:%d gives %q, expected %q\n", x, tt.c, v, s, tt.name) | |||
} | |||
} | |||
} | |||
func TestRandomUUID(t *testing.T) { | |||
m := make(map[string]bool) | |||
for x := 1; x < 32; x++ { | |||
uuid := NewRandom() | |||
s := uuid.String() | |||
if m[s] { | |||
t.Errorf("NewRandom returned duplicated UUID %s\n", s) | |||
} | |||
m[s] = true | |||
if v, _ := uuid.Version(); v != 4 { | |||
t.Errorf("Random UUID of version %s\n", v) | |||
} | |||
if uuid.Variant() != RFC4122 { | |||
t.Errorf("Random UUID is variant %d\n", uuid.Variant()) | |||
} | |||
} | |||
} | |||
func TestNew(t *testing.T) { | |||
m := make(map[string]bool) | |||
for x := 1; x < 32; x++ { | |||
s := New() | |||
if m[s] { | |||
t.Errorf("New returned duplicated UUID %s\n", s) | |||
} | |||
m[s] = true | |||
uuid := Parse(s) | |||
if uuid == nil { | |||
t.Errorf("New returned %q which does not decode\n", s) | |||
continue | |||
} | |||
if v, _ := uuid.Version(); v != 4 { | |||
t.Errorf("Random UUID of version %s\n", v) | |||
} | |||
if uuid.Variant() != RFC4122 { | |||
t.Errorf("Random UUID is variant %d\n", uuid.Variant()) | |||
} | |||
} | |||
} | |||
func clockSeq(t *testing.T, uuid UUID) int { | |||
seq, ok := uuid.ClockSequence() | |||
if !ok { | |||
t.Fatalf("%s: invalid clock sequence\n", uuid) | |||
} | |||
return seq | |||
} | |||
func TestClockSeq(t *testing.T) { | |||
// Fake time.Now for this test to return a monotonically advancing time; restore it at end. | |||
defer func(orig func() time.Time) { timeNow = orig }(timeNow) | |||
monTime := time.Now() | |||
timeNow = func() time.Time { | |||
monTime = monTime.Add(1 * time.Second) | |||
return monTime | |||
} | |||
SetClockSequence(-1) | |||
uuid1 := NewUUID() | |||
uuid2 := NewUUID() | |||
if clockSeq(t, uuid1) != clockSeq(t, uuid2) { | |||
t.Errorf("clock sequence %d != %d\n", clockSeq(t, uuid1), clockSeq(t, uuid2)) | |||
} | |||
SetClockSequence(-1) | |||
uuid2 = NewUUID() | |||
// Just on the very off chance we generated the same sequence | |||
// two times we try again. | |||
if clockSeq(t, uuid1) == clockSeq(t, uuid2) { | |||
SetClockSequence(-1) | |||
uuid2 = NewUUID() | |||
} | |||
if clockSeq(t, uuid1) == clockSeq(t, uuid2) { | |||
t.Errorf("Duplicate clock sequence %d\n", clockSeq(t, uuid1)) | |||
} | |||
SetClockSequence(0x1234) | |||
uuid1 = NewUUID() | |||
if seq := clockSeq(t, uuid1); seq != 0x1234 { | |||
t.Errorf("%s: expected seq 0x1234 got 0x%04x\n", uuid1, seq) | |||
} | |||
} | |||
func TestCoding(t *testing.T) { | |||
text := "7d444840-9dc0-11d1-b245-5ffdce74fad2" | |||
urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2" | |||
data := UUID{ | |||
0x7d, 0x44, 0x48, 0x40, | |||
0x9d, 0xc0, | |||
0x11, 0xd1, | |||
0xb2, 0x45, | |||
0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, | |||
} | |||
if v := data.String(); v != text { | |||
t.Errorf("%x: encoded to %s, expected %s\n", data, v, text) | |||
} | |||
if v := data.URN(); v != urn { | |||
t.Errorf("%x: urn is %s, expected %s\n", data, v, urn) | |||
} | |||
uuid := Parse(text) | |||
if !Equal(uuid, data) { | |||
t.Errorf("%s: decoded to %s, expected %s\n", text, uuid, data) | |||
} | |||
} | |||
func TestVersion1(t *testing.T) { | |||
uuid1 := NewUUID() | |||
uuid2 := NewUUID() | |||
if Equal(uuid1, uuid2) { | |||
t.Errorf("%s:duplicate uuid\n", uuid1) | |||
} | |||
if v, _ := uuid1.Version(); v != 1 { | |||
t.Errorf("%s: version %s expected 1\n", uuid1, v) | |||
} | |||
if v, _ := uuid2.Version(); v != 1 { | |||
t.Errorf("%s: version %s expected 1\n", uuid2, v) | |||
} | |||
n1 := uuid1.NodeID() | |||
n2 := uuid2.NodeID() | |||
if !bytes.Equal(n1, n2) { | |||
t.Errorf("Different nodes %x != %x\n", n1, n2) | |||
} | |||
t1, ok := uuid1.Time() | |||
if !ok { | |||
t.Errorf("%s: invalid time\n", uuid1) | |||
} | |||
t2, ok := uuid2.Time() | |||
if !ok { | |||
t.Errorf("%s: invalid time\n", uuid2) | |||
} | |||
q1, ok := uuid1.ClockSequence() | |||
if !ok { | |||
t.Errorf("%s: invalid clock sequence\n", uuid1) | |||
} | |||
q2, ok := uuid2.ClockSequence() | |||
if !ok { | |||
t.Errorf("%s: invalid clock sequence", uuid2) | |||
} | |||
switch { | |||
case t1 == t2 && q1 == q2: | |||
t.Errorf("time stopped\n") | |||
case t1 > t2 && q1 == q2: | |||
t.Errorf("time reversed\n") | |||
case t1 < t2 && q1 != q2: | |||
t.Errorf("clock sequence chaned unexpectedly\n") | |||
} | |||
} | |||
func TestNodeAndTime(t *testing.T) { | |||
// Time is February 5, 1998 12:30:23.136364800 AM GMT | |||
uuid := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2") | |||
node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2} | |||
ts, ok := uuid.Time() | |||
if ok { | |||
c := time.Unix(ts.UnixTime()) | |||
want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC) | |||
if !c.Equal(want) { | |||
t.Errorf("Got time %v, want %v", c, want) | |||
} | |||
} else { | |||
t.Errorf("%s: bad time\n", uuid) | |||
} | |||
if !bytes.Equal(node, uuid.NodeID()) { | |||
t.Errorf("Expected node %v got %v\n", node, uuid.NodeID()) | |||
} | |||
} | |||
func TestMD5(t *testing.T) { | |||
uuid := NewMD5(NameSpace_DNS, []byte("python.org")).String() | |||
want := "6fa459ea-ee8a-3ca4-894e-db77e160355e" | |||
if uuid != want { | |||
t.Errorf("MD5: got %q expected %q\n", uuid, want) | |||
} | |||
} | |||
func TestSHA1(t *testing.T) { | |||
uuid := NewSHA1(NameSpace_DNS, []byte("python.org")).String() | |||
want := "886313e1-3b8a-5372-9b90-0c9aee199e5d" | |||
if uuid != want { | |||
t.Errorf("SHA1: got %q expected %q\n", uuid, want) | |||
} | |||
} | |||
func TestNodeID(t *testing.T) { | |||
nid := []byte{1, 2, 3, 4, 5, 6} | |||
SetNodeInterface("") | |||
s := NodeInterface() | |||
if s == "" || s == "user" { | |||
t.Errorf("NodeInterface %q after SetInteface\n", s) | |||
} | |||
node1 := NodeID() | |||
if node1 == nil { | |||
t.Errorf("NodeID nil after SetNodeInterface\n", s) | |||
} | |||
SetNodeID(nid) | |||
s = NodeInterface() | |||
if s != "user" { | |||
t.Errorf("Expected NodeInterface %q got %q\n", "user", s) | |||
} | |||
node2 := NodeID() | |||
if node2 == nil { | |||
t.Errorf("NodeID nil after SetNodeID\n", s) | |||
} | |||
if bytes.Equal(node1, node2) { | |||
t.Errorf("NodeID not changed after SetNodeID\n", s) | |||
} else if !bytes.Equal(nid, node2) { | |||
t.Errorf("NodeID is %x, expected %x\n", node2, nid) | |||
} | |||
} | |||
func testDCE(t *testing.T, name string, uuid UUID, domain Domain, id uint32) { | |||
if uuid == nil { | |||
t.Errorf("%s failed\n", name) | |||
return | |||
} | |||
if v, _ := uuid.Version(); v != 2 { | |||
t.Errorf("%s: %s: expected version 2, got %s\n", name, uuid, v) | |||
return | |||
} | |||
if v, ok := uuid.Domain(); !ok || v != domain { | |||
if !ok { | |||
t.Errorf("%s: %d: Domain failed\n", name, uuid) | |||
} else { | |||
t.Errorf("%s: %s: expected domain %d, got %d\n", name, uuid, domain, v) | |||
} | |||
} | |||
if v, ok := uuid.Id(); !ok || v != id { | |||
if !ok { | |||
t.Errorf("%s: %d: Id failed\n", name, uuid) | |||
} else { | |||
t.Errorf("%s: %s: expected id %d, got %d\n", name, uuid, id, v) | |||
} | |||
} | |||
} | |||
func TestDCE(t *testing.T) { | |||
testDCE(t, "NewDCESecurity", NewDCESecurity(42, 12345678), 42, 12345678) | |||
testDCE(t, "NewDCEPerson", NewDCEPerson(), Person, uint32(os.Getuid())) | |||
testDCE(t, "NewDCEGroup", NewDCEGroup(), Group, uint32(os.Getgid())) | |||
} | |||
type badRand struct{} | |||
func (r badRand) Read(buf []byte) (int, error) { | |||
for i, _ := range buf { | |||
buf[i] = byte(i) | |||
} | |||
return len(buf), nil | |||
} | |||
func TestBadRand(t *testing.T) { | |||
SetRand(badRand{}) | |||
uuid1 := New() | |||
uuid2 := New() | |||
if uuid1 != uuid2 { | |||
t.Errorf("execpted duplicates, got %q and %q\n", uuid1, uuid2) | |||
} | |||
SetRand(nil) | |||
uuid1 = New() | |||
uuid2 = New() | |||
if uuid1 == uuid2 { | |||
t.Errorf("unexecpted duplicates, got %q\n", uuid1) | |||
} | |||
} |
@ -0,0 +1,41 @@ | |||
// Copyright 2011 Google Inc. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package uuid | |||
import ( | |||
"encoding/binary" | |||
) | |||
// NewUUID returns a Version 1 UUID based on the current NodeID and clock | |||
// sequence, and the current time. If the NodeID has not been set by SetNodeID | |||
// or SetNodeInterface then it will be set automatically. If the NodeID cannot | |||
// be set NewUUID returns nil. If clock sequence has not been set by | |||
// SetClockSequence then it will be set automatically. If GetTime fails to | |||
// return the current NewUUID returns nil. | |||
func NewUUID() UUID { | |||
if nodeID == nil { | |||
SetNodeInterface("") | |||
} | |||
now, seq, err := GetTime() | |||
if err != nil { | |||
return nil | |||
} | |||
uuid := make([]byte, 16) | |||
time_low := uint32(now & 0xffffffff) | |||
time_mid := uint16((now >> 32) & 0xffff) | |||
time_hi := uint16((now >> 48) & 0x0fff) | |||
time_hi |= 0x1000 // Version 1 | |||
binary.BigEndian.PutUint32(uuid[0:], time_low) | |||
binary.BigEndian.PutUint16(uuid[4:], time_mid) | |||
binary.BigEndian.PutUint16(uuid[6:], time_hi) | |||
binary.BigEndian.PutUint16(uuid[8:], seq) | |||
copy(uuid[10:], nodeID) | |||
return uuid | |||
} |
@ -0,0 +1,25 @@ | |||
// Copyright 2011 Google Inc. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package uuid | |||
// Random returns a Random (Version 4) UUID or panics. | |||
// | |||
// The strength of the UUIDs is based on the strength of the crypto/rand | |||
// package. | |||
// | |||
// A note about uniqueness derived from from the UUID Wikipedia entry: | |||
// | |||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being | |||
// hit by a meteorite is estimated to be one chance in 17 billion, that | |||
// means the probability is about 0.00000000006 (6 × 10−11), | |||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a | |||
// year and having one duplicate. | |||
func NewRandom() UUID { | |||
uuid := make([]byte, 16) | |||
randomBits([]byte(uuid)) | |||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 | |||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 | |||
return uuid | |||
} |