github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/pkg/uuid/uuid.go (about) 1 // Copyright (c) 2017 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 // Package uuid can be used to generate 128 bit UUIDs compatible with 7 // rfc4122. Currently, only version 4 UUIDs, UUIDs generated from random 8 // data, can be created. The package includes functions for generating 9 // UUIDs and for converting them to and from strings. 10 package uuid 11 12 import ( 13 "crypto/rand" 14 "encoding/binary" 15 "errors" 16 "fmt" 17 "io" 18 "strconv" 19 "strings" 20 ) 21 22 // UUID represents a single 128 bit UUID as an array of 16 bytes. 23 type UUID [16]byte 24 25 // UUIDRegex defines a pattern for validating UUIDs 26 const UUIDRegex = "[a-fA-F0-9]{8}-?[a-fA-F0-9]{4}-?4[a-fA-F0-9]{3}-?[8|9|aA|bB][a-fA-F0-9]{3}-?[a-fA-F0-9]{12}" 27 28 var ( 29 // ErrUUIDInvalid indicates that a UIID is invalid. Currently, 30 // returned by uuid.Parse if the string passed to this function 31 // does not contain a valid UUID. 32 ErrUUIDInvalid = errors.New("invalid uuid") 33 ) 34 35 func encode4bytes(n uint64, b []byte) { 36 binary.BigEndian.PutUint32(b, uint32(n)) 37 } 38 39 func encode2bytes(n uint64, b []byte) { 40 binary.BigEndian.PutUint16(b, uint16(n)) 41 } 42 43 func encode1byte(n uint64, b []byte) { 44 b[0] = uint8(n) 45 } 46 47 func encode6bytes(n uint64, b []byte) { 48 d := make([]byte, 8) 49 binary.BigEndian.PutUint64(d, n) 50 copy(b, d[2:]) 51 } 52 53 func stringToBE(s string, b []byte, f func(uint64, []byte)) error { 54 num, err := strconv.ParseUint(s, 16, len(s)*4) 55 if err != nil { 56 return ErrUUIDInvalid 57 } 58 f(num, b) 59 return nil 60 } 61 62 // Parse returns the binary encoding of the UUID passed in the s parameter. 63 // The error ErrUUIDInvalid will be returned if s does not represent a valid 64 // UUID. 65 func Parse(s string) (UUID, error) { 66 var uuid UUID 67 var segmentSizes = [...]int{8, 4, 4, 4, 12} 68 69 segments := strings.Split(s, "-") 70 if len(segments) != len(segmentSizes) { 71 return uuid, ErrUUIDInvalid 72 } 73 74 for i, l := range segmentSizes { 75 if len(segments[i]) != l { 76 return uuid, ErrUUIDInvalid 77 } 78 } 79 80 if err := stringToBE(segments[0], uuid[:4], encode4bytes); err != nil { 81 return uuid, err 82 } 83 if err := stringToBE(segments[1], uuid[4:6], encode2bytes); err != nil { 84 return uuid, err 85 } 86 if err := stringToBE(segments[2], uuid[6:8], encode2bytes); err != nil { 87 return uuid, err 88 } 89 if err := stringToBE(segments[3][:2], uuid[8:9], encode1byte); err != nil { 90 return uuid, err 91 } 92 if err := stringToBE(segments[3][2:], uuid[9:10], encode1byte); err != nil { 93 return uuid, err 94 } 95 if err := stringToBE(segments[4], uuid[10:], encode6bytes); err != nil { 96 return uuid, err 97 } 98 99 return uuid, nil 100 } 101 102 // Generate generates a new v4 UUID, i.e., a random UUID. 103 func Generate() UUID { 104 var u UUID 105 106 _, err := io.ReadFull(rand.Reader, u[:]) 107 if err != nil { 108 panic(fmt.Errorf("Unable to read random data : %v", err)) 109 } 110 111 u[6] = (u[6] & 0x0f) | 0x40 112 u[8] = (u[8] & 0x3f) | 0x80 113 114 return u 115 } 116 117 func (u UUID) String() string { 118 timeLow := binary.BigEndian.Uint32(u[:4]) 119 timeMid := binary.BigEndian.Uint16(u[4:6]) 120 timeHi := binary.BigEndian.Uint16(u[6:8]) 121 clkSeqHi := u[8] 122 clkSeqLow := u[9] 123 buf := make([]byte, 8) 124 copy(buf[2:], u[10:]) 125 node := binary.BigEndian.Uint64(buf) 126 127 return fmt.Sprintf("%08x-%04x-%04x-%02x%02x-%012x", 128 timeLow, timeMid, timeHi, clkSeqHi, clkSeqLow, node) 129 }