<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"

	"golang.org/x/sys/unix"

	"github.com/lxc/lxd/lxd/response"
	"github.com/lxc/lxd/shared"
)

var fileCmd = APIEndpoint{
	Name: "file",
	Path: "files",

	Get:    APIEndpointAction{Handler: fileHandler},
	Post:   APIEndpointAction{Handler: fileHandler},
	Delete: APIEndpointAction{Handler: fileHandler},
}

func fileHandler(r *http.Request) response.Response {
	path := r.FormValue("path")
	if path == "" {
		return response.BadRequest(fmt.Errorf("missing path argument"))
	}

	switch r.Method {
	case "GET":
		return containerFileGet(path, r)
	case "POST":
		return containerFilePost(path, r)
	case "DELETE":
		return containerFileDelete(path, r)
	default:
		return response.NotFound(fmt.Errorf("Method '%s' not found", r.Method))
	}
}

func containerFileGet(path string, r *http.Request) response.Response {
	uid, gid, mode, fType, dirEnts, err := getFileInfo(path)
	if err != nil {
		return response.SmartError(err)
	}

	headers := map[string]string{
		"X-LXD-uid":  fmt.Sprintf("%d", uid),
		"X-LXD-gid":  fmt.Sprintf("%d", gid),
		"X-LXD-mode": fmt.Sprintf("%04o", mode),
		"X-LXD-type": fType,
	}

	if fType == "file" || fType == "symlink" {
		// Make a file response struct
		files := make([]response.FileResponseEntry, 1)
		files[0].Identifier = filepath.Base(path)

		f, err := ioutil.TempFile(filepath.Dir(path), "lxd_getfile_")
		if err != nil {
			return response.SmartError(err)
		}
		defer f.Close()

		if fType == "file" {
			src, err := os.Open(path)
			if err != nil {
				return response.SmartError(err)
			}
			defer src.Close()

			_, err = io.Copy(f, src)
			if err != nil {
				return response.SmartError(err)
			}
		} else {
			target, err := os.Readlink(path)
			if err != nil {
				return response.SmartError(err)
			}

			_, err = f.WriteString(target + "\n")
			if err != nil {
				return response.SmartError(err)
			}
		}

		files[0].Path = f.Name()
		files[0].Filename = filepath.Base(path)

		return response.FileResponse(r, files, headers, true)
	} else if fType == "directory" {
		return response.SyncResponseHeaders(true, dirEnts, headers)
	}

	return response.InternalError(fmt.Errorf("bad file type %s", fType))
}

func containerFilePost(path string, r *http.Request) response.Response {
	// Extract file ownership and mode from headers
	uid, gid, mode, fType, write := shared.ParseLXDFileHeaders(r.Header)

	if !shared.StringInSlice(write, []string{"overwrite", "append"}) {
		return response.BadRequest(fmt.Errorf("Bad file write mode: %s", write))
	}

	if fType == "file" {
		// Write file content to a tempfile
		temp, err := ioutil.TempFile("", "lxd_forkputfile_")
		if err != nil {
			return response.InternalError(err)
		}
		defer func() {
			temp.Close()
			os.Remove(temp.Name())
		}()

		_, err = io.Copy(temp, r.Body)
		if err != nil {
			return response.InternalError(err)
		}

		// Transfer the file into the container
		err = filePush("file", temp.Name(), path, uid, gid, mode, write)
		if err != nil {
			return response.InternalError(err)
		}

		return response.EmptySyncResponse
	} else if fType == "symlink" {
		target, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return response.InternalError(err)
		}

		err = filePush("symlink", string(target), path, uid, gid, mode, write)
		if err != nil {
			return response.InternalError(err)
		}
		return response.EmptySyncResponse
	} else if fType == "directory" {
		err := filePush("directory", "", path, uid, gid, mode, write)
		if err != nil {
			return response.InternalError(err)
		}
		return response.EmptySyncResponse
	}

	return response.BadRequest(fmt.Errorf("Bad file type: %s", fType))
}

func containerFileDelete(path string, r *http.Request) response.Response {
	err := os.Remove(path)
	if err != nil {
		return response.SmartError(err)
	}

	return response.EmptySyncResponse
}

func getFileInfo(path string) (int64, int64, os.FileMode, string, []string, error) {
	var stat unix.Stat_t

	err := os.Chdir("/")
	if err != nil {
		return -1, -1, 0, "", nil, err
	}

	fi, err := os.Lstat(path)
	if err != nil {
		return -1, -1, 0, "", nil, err
	}

	err = unix.Lstat(path, &stat)
	if err != nil {
		return -1, -1, 0, "", nil, err
	}

	var fType string
	var dirEnts []string

	if fi.Mode().IsDir() {
		fType = "directory"

		f, err := os.Open(path)
		if err != nil {
			return -1, -1, 0, "", nil, err
		}

		dirEnts, err = f.Readdirnames(0)
		if err != nil {
			return -1, -1, 0, "", nil, err
		}

	} else {
		if fi.Mode()&os.ModeSymlink != 0 {
			fType = "symlink"
		} else {
			fType = "file"
		}
	}

	// 0xFFF = 0b7777
	return int64(stat.Uid), int64(stat.Gid), fi.Mode() & 0xFFF, fType, dirEnts, nil
}

func filePush(fType string, srcpath string, dstpath string, uid int64, gid int64, mode int, write string) error {
	switch fType {
	case "file":
		if !shared.PathExists(dstpath) {
			if uid == -1 {
				uid = 0
			}

			if gid == -1 {
				gid = 0
			}

			if mode == -1 {
				mode = 0
			}
		}

		flags := os.O_CREATE | os.O_WRONLY

		if write == "overwrite" {
			flags |= os.O_TRUNC
		} else if write == "append" {
			flags |= os.O_APPEND
		}

		dst, err := os.OpenFile(dstpath, flags, os.FileMode(mode))
		if err != nil {
			return err
		}
		defer dst.Close()

		src, err := os.Open(srcpath)
		if err != nil {
			return err
		}
		defer src.Close()

		_, err = io.Copy(dst, src)
		if err != nil {
			return err
		}

		err = os.Chown(dst.Name(), int(uid), int(gid))
		if err != nil {
			return err
		}

		return nil
	case "symlink":
		if uid == -1 {
			uid = 0
		}

		if gid == -1 {
			gid = 0
		}

		err := os.Symlink(srcpath, dstpath)
		if err != nil {
			return err
		}

		err = os.Lchown(dstpath, int(uid), int(gid))
		if err != nil {
			return err
		}

		return nil
	case "directory":
		if uid == -1 {
			uid = 0
		}

		if gid == -1 {
			gid = 0
		}

		if mode == -1 {
			mode = 0
		}

		err := os.MkdirAll(dstpath, os.FileMode(mode))
		if err != nil {
			return err
		}

		err = os.Chown(dstpath, int(uid), int(gid))
		if err != nil {
			return err
		}

		return nil
	}

	return fmt.Errorf("Bad file type: %s", fType)
}
<commit_msg>lxd-agent: Function name consistency<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"

	"golang.org/x/sys/unix"

	"github.com/lxc/lxd/lxd/response"
	"github.com/lxc/lxd/shared"
)

var fileCmd = APIEndpoint{
	Name: "file",
	Path: "files",

	Get:    APIEndpointAction{Handler: fileHandler},
	Post:   APIEndpointAction{Handler: fileHandler},
	Delete: APIEndpointAction{Handler: fileHandler},
}

func fileHandler(r *http.Request) response.Response {
	path := r.FormValue("path")
	if path == "" {
		return response.BadRequest(fmt.Errorf("missing path argument"))
	}

	switch r.Method {
	case "GET":
		return fileGet(path, r)
	case "POST":
		return filePost(path, r)
	case "DELETE":
		return fileDelete(path, r)
	default:
		return response.NotFound(fmt.Errorf("Method '%s' not found", r.Method))
	}
}

func fileGet(path string, r *http.Request) response.Response {
	uid, gid, mode, fType, dirEnts, err := getFileInfo(path)
	if err != nil {
		return response.SmartError(err)
	}

	headers := map[string]string{
		"X-LXD-uid":  fmt.Sprintf("%d", uid),
		"X-LXD-gid":  fmt.Sprintf("%d", gid),
		"X-LXD-mode": fmt.Sprintf("%04o", mode),
		"X-LXD-type": fType,
	}

	if fType == "file" || fType == "symlink" {
		// Make a file response struct
		files := make([]response.FileResponseEntry, 1)
		files[0].Identifier = filepath.Base(path)

		f, err := ioutil.TempFile(filepath.Dir(path), "lxd_getfile_")
		if err != nil {
			return response.SmartError(err)
		}
		defer f.Close()

		if fType == "file" {
			src, err := os.Open(path)
			if err != nil {
				return response.SmartError(err)
			}
			defer src.Close()

			_, err = io.Copy(f, src)
			if err != nil {
				return response.SmartError(err)
			}
		} else {
			target, err := os.Readlink(path)
			if err != nil {
				return response.SmartError(err)
			}

			_, err = f.WriteString(target + "\n")
			if err != nil {
				return response.SmartError(err)
			}
		}

		files[0].Path = f.Name()
		files[0].Filename = filepath.Base(path)

		return response.FileResponse(r, files, headers, true)
	} else if fType == "directory" {
		return response.SyncResponseHeaders(true, dirEnts, headers)
	}

	return response.InternalError(fmt.Errorf("bad file type %s", fType))
}

func filePost(path string, r *http.Request) response.Response {
	// Extract file ownership and mode from headers
	uid, gid, mode, fType, write := shared.ParseLXDFileHeaders(r.Header)

	if !shared.StringInSlice(write, []string{"overwrite", "append"}) {
		return response.BadRequest(fmt.Errorf("Bad file write mode: %s", write))
	}

	if fType == "file" {
		// Write file content to a tempfile
		temp, err := ioutil.TempFile("", "lxd_forkputfile_")
		if err != nil {
			return response.InternalError(err)
		}
		defer func() {
			temp.Close()
			os.Remove(temp.Name())
		}()

		_, err = io.Copy(temp, r.Body)
		if err != nil {
			return response.InternalError(err)
		}

		// Transfer the file into the container
		err = filePush("file", temp.Name(), path, uid, gid, mode, write)
		if err != nil {
			return response.InternalError(err)
		}

		return response.EmptySyncResponse
	} else if fType == "symlink" {
		target, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return response.InternalError(err)
		}

		err = filePush("symlink", string(target), path, uid, gid, mode, write)
		if err != nil {
			return response.InternalError(err)
		}
		return response.EmptySyncResponse
	} else if fType == "directory" {
		err := filePush("directory", "", path, uid, gid, mode, write)
		if err != nil {
			return response.InternalError(err)
		}
		return response.EmptySyncResponse
	}

	return response.BadRequest(fmt.Errorf("Bad file type: %s", fType))
}

func fileDelete(path string, r *http.Request) response.Response {
	err := os.Remove(path)
	if err != nil {
		return response.SmartError(err)
	}

	return response.EmptySyncResponse
}

func getFileInfo(path string) (int64, int64, os.FileMode, string, []string, error) {
	var stat unix.Stat_t

	err := os.Chdir("/")
	if err != nil {
		return -1, -1, 0, "", nil, err
	}

	fi, err := os.Lstat(path)
	if err != nil {
		return -1, -1, 0, "", nil, err
	}

	err = unix.Lstat(path, &stat)
	if err != nil {
		return -1, -1, 0, "", nil, err
	}

	var fType string
	var dirEnts []string

	if fi.Mode().IsDir() {
		fType = "directory"

		f, err := os.Open(path)
		if err != nil {
			return -1, -1, 0, "", nil, err
		}

		dirEnts, err = f.Readdirnames(0)
		if err != nil {
			return -1, -1, 0, "", nil, err
		}

	} else {
		if fi.Mode()&os.ModeSymlink != 0 {
			fType = "symlink"
		} else {
			fType = "file"
		}
	}

	// 0xFFF = 0b7777
	return int64(stat.Uid), int64(stat.Gid), fi.Mode() & 0xFFF, fType, dirEnts, nil
}

func filePush(fType string, srcpath string, dstpath string, uid int64, gid int64, mode int, write string) error {
	switch fType {
	case "file":
		if !shared.PathExists(dstpath) {
			if uid == -1 {
				uid = 0
			}

			if gid == -1 {
				gid = 0
			}

			if mode == -1 {
				mode = 0
			}
		}

		flags := os.O_CREATE | os.O_WRONLY

		if write == "overwrite" {
			flags |= os.O_TRUNC
		} else if write == "append" {
			flags |= os.O_APPEND
		}

		dst, err := os.OpenFile(dstpath, flags, os.FileMode(mode))
		if err != nil {
			return err
		}
		defer dst.Close()

		src, err := os.Open(srcpath)
		if err != nil {
			return err
		}
		defer src.Close()

		_, err = io.Copy(dst, src)
		if err != nil {
			return err
		}

		err = os.Chown(dst.Name(), int(uid), int(gid))
		if err != nil {
			return err
		}

		return nil
	case "symlink":
		if uid == -1 {
			uid = 0
		}

		if gid == -1 {
			gid = 0
		}

		err := os.Symlink(srcpath, dstpath)
		if err != nil {
			return err
		}

		err = os.Lchown(dstpath, int(uid), int(gid))
		if err != nil {
			return err
		}

		return nil
	case "directory":
		if uid == -1 {
			uid = 0
		}

		if gid == -1 {
			gid = 0
		}

		if mode == -1 {
			mode = 0
		}

		err := os.MkdirAll(dstpath, os.FileMode(mode))
		if err != nil {
			return err
		}

		err = os.Chown(dstpath, int(uid), int(gid))
		if err != nil {
			return err
		}

		return nil
	}

	return fmt.Errorf("Bad file type: %s", fType)
}
<|endoftext|>


<commit_before>// Copyright 2015 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lzma

import (
	"errors"
	"fmt"

	"github.com/ulikunitz/xz/hash"
)

/* For compression we need to find byte sequences that match the byte
 * sequence at the dictionary head. A hash table is a simple method to
 * provide this capability.
 */

// The minimum is somehow arbitrary but the maximum is limited by the
// memory requirements of the hash table.
const (
	minTableExponent = 9
	maxTableExponent = 20
)

// newRoller contains the function used to create an instance of the
// hash.Roller.
var newRoller = func(n int) hash.Roller { return hash.NewCyclicPoly(n) }

// hashTable stores the hash table including the rolling hash method.
//
// We implement chained hashing into a circular buffer. Each entry in
// the circular buffer stores the delta distance to the next position with a
// word that has the same hash value.
type hashTable struct {
	// actual hash table
	t []int64
	// circular list data with the offset to the next word
	data  []uint32
	front int
	// mask for computing the index for the hash table
	mask uint64
	// hash offset; initial value is -int64(wordLen)
	hoff int64
	// length of the hashed word
	wordLen int
	// hash roller for computing the hash values for the Write
	// method
	wr hash.Roller
	// hash roller for computing arbitrary hashes
	hr hash.Roller
}

// hashTableExponent derives the hash table exponent from the dictionary
// capacity.
func hashTableExponent(n uint32) int {
	e := 30 - nlz32(n)
	switch {
	case e < minTableExponent:
		e = minTableExponent
	case e > maxTableExponent:
		e = maxTableExponent
	}
	return e
}

// newHashTable creates a new hash table for words of length wordLen
func newHashTable(capacity int, wordLen int) (t *hashTable, err error) {
	if !(0 < capacity) {
		return nil, errors.New(
			"newHashTable: capacity must not be negative")
	}
	exp := hashTableExponent(uint32(capacity))
	if !(1 <= wordLen && wordLen <= 4) {
		return nil, errors.New("newHashTable: " +
			"argument wordLen out of range")
	}
	n := 1 << uint(exp)
	if n <= 0 {
		panic("newHashTable: exponent is too large")
	}
	t = &hashTable{
		t:       make([]int64, n),
		data:    make([]uint32, capacity),
		mask:    (uint64(1) << uint(exp)) - 1,
		hoff:    -int64(wordLen),
		wordLen: wordLen,
		wr:      newRoller(wordLen),
		hr:      newRoller(wordLen),
	}
	return t, nil
}

// Reset puts hashTable back into a pristine condition.
func (t *hashTable) Reset() {
	for i := range t.t {
		t.t[i] = 0
	}
	t.front = 0
	t.hoff = -int64(t.wordLen)
	t.wr = newRoller(t.wordLen)
	t.hr = newRoller(t.wordLen)
}

// Pos returns the number of all byte written already to the matcher. We
// call it in the code also absolute position.
func (t *hashTable) Pos() int64 {
	return t.hoff + int64(t.wordLen)
}

// buffered returns the number of bytes that are currently hashed.
func (t *hashTable) buffered() int {
	n := t.hoff + 1
	switch {
	case n <= 0:
		return 0
	case n >= int64(len(t.data)):
		return len(t.data)
	}
	return int(n)
}

// addIndex adds n to an index ensuring that is stays inside the
// circular buffer for the hash chain.
func (t *hashTable) addIndex(i, n int) int {
	i += n - len(t.data)
	if i < 0 {
		i += len(t.data)
	}
	return i
}

// putDelta puts the delta instance at the current front of the circular
// chain buffer.
func (t *hashTable) putDelta(delta uint32) {
	t.data[t.front] = delta
	t.front = t.addIndex(t.front, 1)
}

// putEntry puts a new entry into the hash table. If there is already a
// value stored it is moved into the circular chain buffer.
func (t *hashTable) putEntry(h uint64, pos int64) {
	if pos < 0 {
		return
	}
	i := h & t.mask
	old := t.t[i] - 1
	t.t[i] = pos + 1
	var delta int64
	if old >= 0 {
		delta = pos - old
		if delta > 1<<32-1 || delta > int64(t.buffered()) {
			delta = 0
		}
	}
	t.putDelta(uint32(delta))
}

// WriteByte converts a single byte into a hash and puts them into the hash
// table.
func (t *hashTable) WriteByte(b byte) error {
	h := t.wr.RollByte(b)
	t.hoff++
	t.putEntry(h, t.hoff)
	return nil
}

// Write converts the bytes provided into hash tables and stores the
// abbreviated offsets into the hash table. The function will never return an
// error.
func (t *hashTable) Write(p []byte) (n int, err error) {
	for _, b := range p {
		// WriteByte doesn't generate an error.
		t.WriteByte(b)
	}
	return len(p), nil
}

// maxMatches limits the number of matches provided by the Matches
// function. This controls the speed of the overall encoding. This limit
// might be better implemented at a higher level, because it doesn't
// care for the current dictionary head.
const maxMatches = 32

// getMatches returns the potential positions for a specific hash.
func (t *hashTable) getMatches(h uint64) (positions []int64) {
	if t.hoff < 0 {
		return nil
	}
	buffered := t.buffered()
	tailPos := t.hoff + 1 - int64(buffered)
	rear := t.front - buffered
	if rear >= 0 {
		rear -= len(t.data)
	}
	positions = make([]int64, 0, maxMatches)
	// get the slot for the hash
	pos := t.t[h&t.mask] - 1
	delta := pos - tailPos
	for {
		if delta < 0 {
			return positions
		}
		positions = append(positions, tailPos+delta)
		if len(positions) >= maxMatches {
			return positions
		}
		i := rear + int(delta)
		if i < 0 {
			i += len(t.data)
		}
		u := t.data[i]
		if u == 0 {
			return positions
		}
		delta -= int64(u)
	}
}

// hash computes the rolling hash for the word stored in p. For correct
// results its length must be equal to t.wordLen.
func (t *hashTable) hash(p []byte) uint64 {
	var h uint64
	for _, b := range p {
		h = t.hr.RollByte(b)
	}
	return h
}

// WordLen returns the length of the words supported by the Matches
// function.
func (t *hashTable) WordLen() int {
	return t.wordLen
}

// Matches returns the positions of potential matches. Those matches
// have to be verified, whether they are indeed matching. The byte slice
// p must have word length of the hash table.
func (t *hashTable) Matches(p []byte) (positions []int64) {
	if len(p) != t.wordLen {
		panic(fmt.Errorf(
			"Matches: byte slice must have length %d", t.wordLen))
	}
	h := t.hash(p)
	return t.getMatches(h)
}
<commit_msg>lzma: changed interface of Matches method<commit_after>// Copyright 2015 Ulrich Kunitz. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lzma

import (
	"errors"
	"fmt"

	"github.com/ulikunitz/xz/hash"
)

/* For compression we need to find byte sequences that match the byte
 * sequence at the dictionary head. A hash table is a simple method to
 * provide this capability.
 */

// The minimum is somehow arbitrary but the maximum is limited by the
// memory requirements of the hash table.
const (
	minTableExponent = 9
	maxTableExponent = 20
)

// newRoller contains the function used to create an instance of the
// hash.Roller.
var newRoller = func(n int) hash.Roller { return hash.NewCyclicPoly(n) }

// hashTable stores the hash table including the rolling hash method.
//
// We implement chained hashing into a circular buffer. Each entry in
// the circular buffer stores the delta distance to the next position with a
// word that has the same hash value.
type hashTable struct {
	// actual hash table
	t []int64
	// circular list data with the offset to the next word
	data  []uint32
	front int
	// mask for computing the index for the hash table
	mask uint64
	// hash offset; initial value is -int64(wordLen)
	hoff int64
	// length of the hashed word
	wordLen int
	// hash roller for computing the hash values for the Write
	// method
	wr hash.Roller
	// hash roller for computing arbitrary hashes
	hr hash.Roller
}

// hashTableExponent derives the hash table exponent from the dictionary
// capacity.
func hashTableExponent(n uint32) int {
	e := 30 - nlz32(n)
	switch {
	case e < minTableExponent:
		e = minTableExponent
	case e > maxTableExponent:
		e = maxTableExponent
	}
	return e
}

// newHashTable creates a new hash table for words of length wordLen
func newHashTable(capacity int, wordLen int) (t *hashTable, err error) {
	if !(0 < capacity) {
		return nil, errors.New(
			"newHashTable: capacity must not be negative")
	}
	exp := hashTableExponent(uint32(capacity))
	if !(1 <= wordLen && wordLen <= 4) {
		return nil, errors.New("newHashTable: " +
			"argument wordLen out of range")
	}
	n := 1 << uint(exp)
	if n <= 0 {
		panic("newHashTable: exponent is too large")
	}
	t = &hashTable{
		t:       make([]int64, n),
		data:    make([]uint32, capacity),
		mask:    (uint64(1) << uint(exp)) - 1,
		hoff:    -int64(wordLen),
		wordLen: wordLen,
		wr:      newRoller(wordLen),
		hr:      newRoller(wordLen),
	}
	return t, nil
}

// Reset puts hashTable back into a pristine condition.
func (t *hashTable) Reset() {
	for i := range t.t {
		t.t[i] = 0
	}
	t.front = 0
	t.hoff = -int64(t.wordLen)
	t.wr = newRoller(t.wordLen)
	t.hr = newRoller(t.wordLen)
}

// Pos returns the number of all byte written already to the matcher. We
// call it in the code also absolute position.
func (t *hashTable) Pos() int64 {
	return t.hoff + int64(t.wordLen)
}

// buffered returns the number of bytes that are currently hashed.
func (t *hashTable) buffered() int {
	n := t.hoff + 1
	switch {
	case n <= 0:
		return 0
	case n >= int64(len(t.data)):
		return len(t.data)
	}
	return int(n)
}

// addIndex adds n to an index ensuring that is stays inside the
// circular buffer for the hash chain.
func (t *hashTable) addIndex(i, n int) int {
	i += n - len(t.data)
	if i < 0 {
		i += len(t.data)
	}
	return i
}

// putDelta puts the delta instance at the current front of the circular
// chain buffer.
func (t *hashTable) putDelta(delta uint32) {
	t.data[t.front] = delta
	t.front = t.addIndex(t.front, 1)
}

// putEntry puts a new entry into the hash table. If there is already a
// value stored it is moved into the circular chain buffer.
func (t *hashTable) putEntry(h uint64, pos int64) {
	if pos < 0 {
		return
	}
	i := h & t.mask
	old := t.t[i] - 1
	t.t[i] = pos + 1
	var delta int64
	if old >= 0 {
		delta = pos - old
		if delta > 1<<32-1 || delta > int64(t.buffered()) {
			delta = 0
		}
	}
	t.putDelta(uint32(delta))
}

// WriteByte converts a single byte into a hash and puts them into the hash
// table.
func (t *hashTable) WriteByte(b byte) error {
	h := t.wr.RollByte(b)
	t.hoff++
	t.putEntry(h, t.hoff)
	return nil
}

// Write converts the bytes provided into hash tables and stores the
// abbreviated offsets into the hash table. The function will never return an
// error.
func (t *hashTable) Write(p []byte) (n int, err error) {
	for _, b := range p {
		// WriteByte doesn't generate an error.
		t.WriteByte(b)
	}
	return len(p), nil
}

// getMatches the matches for a specific hash. The functions returns the
// number of positions found.
func (t *hashTable) getMatches(h uint64, positions []int64) (n int) {
	if t.hoff < 0 || len(positions) == 0 {
		return 0
	}
	buffered := t.buffered()
	tailPos := t.hoff + 1 - int64(buffered)
	rear := t.front - buffered
	if rear >= 0 {
		rear -= len(t.data)
	}
	// get the slot for the hash
	pos := t.t[h&t.mask] - 1
	delta := pos - tailPos
	for {
		if delta < 0 {
			return n
		}
		positions[n] = tailPos + delta
		n++
		if n >= len(positions) {
			return n
		}
		i := rear + int(delta)
		if i < 0 {
			i += len(t.data)
		}
		u := t.data[i]
		if u == 0 {
			return n
		}
		delta -= int64(u)
	}
}

// hash computes the rolling hash for the word stored in p. For correct
// results its length must be equal to t.wordLen.
func (t *hashTable) hash(p []byte) uint64 {
	var h uint64
	for _, b := range p {
		h = t.hr.RollByte(b)
	}
	return h
}

// WordLen returns the length of the words supported by the Matches
// function.
func (t *hashTable) WordLen() int {
	return t.wordLen
}

// Matches fills the positions slice with potential matches. The
// functions returns the number of positions filled into positions. The
// byte slice p must have word length of the hash table.
func (t *hashTable) Matches(p []byte, positions []int64) int {
	if len(p) != t.wordLen {
		panic(fmt.Errorf(
			"Matches: byte slice must have length %d", t.wordLen))
	}
	h := t.hash(p)
	return t.getMatches(h, positions)
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package defines constants representing the lexical
// tokens of the Go programming language and basic operations
// on tokens (printing, predicates).
//
package token

import (
	"fmt";
	"strconv";
)

// Token is the set of lexical tokens of the Go programming language.
type Token int

// The list of tokens.
const (
	// Special tokens
	ILLEGAL Token = iota;
	EOF;
	COMMENT;

	// Identifiers and basic type literals
	// (these tokens stand for classes of literals)
	literal_beg;
	IDENT;
	INT;
	FLOAT;
	CHAR;
	STRING;
	literal_end;

	// Operators and delimiters
	operator_beg;
	ADD;
	SUB;
	MUL;
	QUO;
	REM;

	AND;
	OR;
	XOR;
	SHL;
	SHR;
	AND_NOT;

	ADD_ASSIGN;
	SUB_ASSIGN;
	MUL_ASSIGN;
	QUO_ASSIGN;
	REM_ASSIGN;

	AND_ASSIGN;
	OR_ASSIGN;
	XOR_ASSIGN;
	SHL_ASSIGN;
	SHR_ASSIGN;
	AND_NOT_ASSIGN;

	LAND;
	LOR;
	ARROW;
	INC;
	DEC;

	EQL;
	LSS;
	GTR;
	ASSIGN;
	NOT;

	NEQ;
	LEQ;
	GEQ;
	DEFINE;
	ELLIPSIS;

	LPAREN;
	LBRACK;
	LBRACE;
	COMMA;
	PERIOD;

	RPAREN;
	RBRACK;
	RBRACE;
	SEMICOLON;
	COLON;
	operator_end;

	// Keywords
	keyword_beg;
	BREAK;
	CASE;
	CHAN;
	CONST;
	CONTINUE;

	DEFAULT;
	DEFER;
	ELSE;
	FALLTHROUGH;
	FOR;

	FUNC;
	GO;
	GOTO;
	IF;
	IMPORT;

	INTERFACE;
	MAP;
	PACKAGE;
	RANGE;
	RETURN;

	SELECT;
	STRUCT;
	SWITCH;
	TYPE;
	VAR;
	keyword_end;
)

// At the moment we have no array literal syntax that lets us describe
// the index for each element - use a map for now to make sure they are
// in sync.
var tokens = map [Token] string {
	ILLEGAL : "ILLEGAL",

	EOF : "EOF",
	COMMENT : "COMMENT",

	IDENT : "IDENT",
	INT : "INT",
	FLOAT : "FLOAT",
	CHAR : "CHAR",
	STRING : "STRING",

	ADD : "+",
	SUB : "-",
	MUL : "*",
	QUO : "/",
	REM : "%",

	AND : "&",
	OR : "|",
	XOR : "^",
	SHL : "<<",
	SHR : ">>",
	AND_NOT : "&^",

	ADD_ASSIGN : "+=",
	SUB_ASSIGN : "-=",
	MUL_ASSIGN : "*=",
	QUO_ASSIGN : "/=",
	REM_ASSIGN : "%=",

	AND_ASSIGN : "&=",
	OR_ASSIGN : "|=",
	XOR_ASSIGN : "^=",
	SHL_ASSIGN : "<<=",
	SHR_ASSIGN : ">>=",
	AND_NOT_ASSIGN : "&^=",

	LAND : "&&",
	LOR : "||",
	ARROW : "<-",
	INC : "++",
	DEC : "--",

	EQL : "==",
	LSS : "<",
	GTR : ">",
	ASSIGN : "=",
	NOT : "!",

	NEQ : "!=",
	LEQ : "<=",
	GEQ : ">=",
	DEFINE : ":=",
	ELLIPSIS : "...",

	LPAREN : "(",
	LBRACK : "[",
	LBRACE : "{",
	COMMA : ",",
	PERIOD : ".",

	RPAREN : ")",
	RBRACK : "]",
	RBRACE : "}",
	SEMICOLON : ";",
	COLON : ":",

	BREAK : "break",
	CASE : "case",
	CHAN : "chan",
	CONST : "const",
	CONTINUE : "continue",

	DEFAULT : "default",
	DEFER : "defer",
	ELSE : "else",
	FALLTHROUGH : "fallthrough",
	FOR : "for",

	FUNC : "func",
	GO : "go",
	GOTO : "goto",
	IF : "if",
	IMPORT : "import",

	INTERFACE : "interface",
	MAP : "map",
	PACKAGE : "package",
	RANGE : "range",
	RETURN : "return",

	SELECT : "select",
	STRUCT : "struct",
	SWITCH : "switch",
	TYPE : "type",
	VAR : "var",
}

// String returns the string corresponding to the token tok.
// For operators, delimiters, and keywords the string is the actual
// token character sequence (e.g., for the token ADD, the string is
// "+"). For all other tokens the string corresponds to the token
// constant name (e.g. for the token IDENT, the string is "IDENT").
//
func (tok Token) String() string {
	if str, exists := tokens[tok]; exists {
		return str;
	}
	return "token(" + strconv.Itoa(int(tok)) + ")";
}

// A set of constants for precedence-based expression parsing.
// Non-operators have lowest precedence, followed by operators
// starting with precedence 1 up to unary operators. The highest
// precedence corresponds serves as "catch-all" precedence for
// selector, indexing, and other operator and delimiter tokens.
//
const (
	LowestPrec = 0;  // non-operators
	UnaryPrec = 7;
	HighestPrec = 8;
)

// Precedence returns the operator precedence of the binary
// operator op. If op is not a binary operator, the result
// is LowestPrecedence.
//
func (op Token) Precedence() int {
	switch op {
	case LOR:
		return 1;
	case LAND:
		return 2;
	case ARROW:
		return 3;
	case EQL, NEQ, LSS, LEQ, GTR, GEQ:
		return 4;
	case ADD, SUB, OR, XOR:
		return 5;
	case MUL, QUO, REM, SHL, SHR, AND, AND_NOT:
		return 6;
	}
	return LowestPrec;
}

var keywords map [string] Token;

func init() {
	keywords = make(map [string] Token);
	for i := keyword_beg + 1; i < keyword_end; i++ {
		keywords[tokens[i]] = i;
	}
}

// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
//
func Lookup(ident []byte) Token {
	// TODO Maps with []byte key are illegal because []byte does not
	//      support == . Should find a more efficient solution eventually.
	if tok, is_keyword := keywords[string(ident)]; is_keyword {
		return tok;
	}
	return IDENT;
}

// Predicates

// IsLiteral returns true for tokens corresponding to identifiers
// and basic type literals; returns false otherwise.
//
func (tok Token) IsLiteral() bool {
	return literal_beg < tok && tok < literal_end;
}

// IsOperator returns true for tokens corresponding to operators and
// delimiters; returns false otherwise.
//
func (tok Token) IsOperator() bool {
	return operator_beg < tok && tok < operator_end;
}

// IsKeyword returns true for tokens corresponding to keywords;
// returns false otherwise.
//
func (tok Token) IsKeyword() bool {
	return keyword_beg < tok && tok < keyword_end;
}

// Token source positions are represented by a Position value.
// A Position is valid if the line number is > 0.
//
type Position struct {
	Filename string;  // filename, if any
	Offset int;  // byte offset, starting at 0
	Line int;  // line number, starting at 1
	Column int;  // column number, starting at 1 (character count)
}

// Pos is an accessor method for anonymous Position fields.
// It returns its receiver.
//
func (pos *Position) Pos() Position {
	return *pos;
}

// IsValid returns true if the position is valid.
func (pos *Position) IsValid() bool {
	return pos.Line > 0
}

func (pos *Position) String() string {
	if pos != nil {
		s := pos.Filename;
		if pos.IsValid() {
			if s != "" {
				s += ":";
			}
			s += fmt.Sprintf("%d:%d", pos.Line, pos.Column);
		}
		if s != "" {
			return s;
		}
	}
	return "<unknown position>";
}
<commit_msg>documentation edits: add comments showing Go syntax for each token. move doc comments below hidden begin constants<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package defines constants representing the lexical
// tokens of the Go programming language and basic operations
// on tokens (printing, predicates).
//
package token

import (
	"fmt";
	"strconv";
)

// Token is the set of lexical tokens of the Go programming language.
type Token int

// The list of tokens.
const (
	// Special tokens
	ILLEGAL Token = iota;
	EOF;
	COMMENT;

	literal_beg;
	// Identifiers and basic type literals
	// (these tokens stand for classes of literals)
	IDENT;		// main
	INT;		// 12345
	FLOAT;		// 123.45
	CHAR;		// 'a'
	STRING;		// "abc"
	literal_end;

	operator_beg;
	// Operators and delimiters
	ADD;		// +
	SUB;		// -
	MUL;		// *
	QUO;		// /
	REM;		// %

	AND;		// &
	OR;		// |
	XOR;		// ^
	SHL;		// <<
	SHR;		// >>
	AND_NOT;	// &^

	ADD_ASSIGN;	// +=
	SUB_ASSIGN;	// -=
	MUL_ASSIGN;	// *=
	QUO_ASSIGN;	// /=
	REM_ASSIGN;	// %=

	AND_ASSIGN;	// &=
	OR_ASSIGN;	// |=
	XOR_ASSIGN;	// ^=
	SHL_ASSIGN;	// <<=
	SHR_ASSIGN;	// >>=
	AND_NOT_ASSIGN;	// &^=

	LAND;		// &&
	LOR;		// ||
	ARROW;		// <-
	INC;		// ++
	DEC;		// --

	EQL;		// ==
	LSS;		// <
	GTR;		// >
	ASSIGN;		// =
	NOT;		// !

	NEQ;		// !=
	LEQ;		// <=
	GEQ;		// >=
	DEFINE;		// :=
	ELLIPSIS;	// ...

	LPAREN;		// (
	LBRACK;		// [
	LBRACE;		// {
	COMMA;		// ,
	PERIOD;		// .

	RPAREN;		// )
	RBRACK;		// ]
	RBRACE;		// }
	SEMICOLON;	// ;
	COLON;		// :
	operator_end;

	keyword_beg;
	// Keywords
	BREAK;
	CASE;
	CHAN;
	CONST;
	CONTINUE;

	DEFAULT;
	DEFER;
	ELSE;
	FALLTHROUGH;
	FOR;

	FUNC;
	GO;
	GOTO;
	IF;
	IMPORT;

	INTERFACE;
	MAP;
	PACKAGE;
	RANGE;
	RETURN;

	SELECT;
	STRUCT;
	SWITCH;
	TYPE;
	VAR;
	keyword_end;
)

// At the moment we have no array literal syntax that lets us describe
// the index for each element - use a map for now to make sure they are
// in sync.
var tokens = map [Token] string {
	ILLEGAL : "ILLEGAL",

	EOF : "EOF",
	COMMENT : "COMMENT",

	IDENT : "IDENT",
	INT : "INT",
	FLOAT : "FLOAT",
	CHAR : "CHAR",
	STRING : "STRING",

	ADD : "+",
	SUB : "-",
	MUL : "*",
	QUO : "/",
	REM : "%",

	AND : "&",
	OR : "|",
	XOR : "^",
	SHL : "<<",
	SHR : ">>",
	AND_NOT : "&^",

	ADD_ASSIGN : "+=",
	SUB_ASSIGN : "-=",
	MUL_ASSIGN : "*=",
	QUO_ASSIGN : "/=",
	REM_ASSIGN : "%=",

	AND_ASSIGN : "&=",
	OR_ASSIGN : "|=",
	XOR_ASSIGN : "^=",
	SHL_ASSIGN : "<<=",
	SHR_ASSIGN : ">>=",
	AND_NOT_ASSIGN : "&^=",

	LAND : "&&",
	LOR : "||",
	ARROW : "<-",
	INC : "++",
	DEC : "--",

	EQL : "==",
	LSS : "<",
	GTR : ">",
	ASSIGN : "=",
	NOT : "!",

	NEQ : "!=",
	LEQ : "<=",
	GEQ : ">=",
	DEFINE : ":=",
	ELLIPSIS : "...",

	LPAREN : "(",
	LBRACK : "[",
	LBRACE : "{",
	COMMA : ",",
	PERIOD : ".",

	RPAREN : ")",
	RBRACK : "]",
	RBRACE : "}",
	SEMICOLON : ";",
	COLON : ":",

	BREAK : "break",
	CASE : "case",
	CHAN : "chan",
	CONST : "const",
	CONTINUE : "continue",

	DEFAULT : "default",
	DEFER : "defer",
	ELSE : "else",
	FALLTHROUGH : "fallthrough",
	FOR : "for",

	FUNC : "func",
	GO : "go",
	GOTO : "goto",
	IF : "if",
	IMPORT : "import",

	INTERFACE : "interface",
	MAP : "map",
	PACKAGE : "package",
	RANGE : "range",
	RETURN : "return",

	SELECT : "select",
	STRUCT : "struct",
	SWITCH : "switch",
	TYPE : "type",
	VAR : "var",
}

// String returns the string corresponding to the token tok.
// For operators, delimiters, and keywords the string is the actual
// token character sequence (e.g., for the token ADD, the string is
// "+"). For all other tokens the string corresponds to the token
// constant name (e.g. for the token IDENT, the string is "IDENT").
//
func (tok Token) String() string {
	if str, exists := tokens[tok]; exists {
		return str;
	}
	return "token(" + strconv.Itoa(int(tok)) + ")";
}

// A set of constants for precedence-based expression parsing.
// Non-operators have lowest precedence, followed by operators
// starting with precedence 1 up to unary operators. The highest
// precedence corresponds serves as "catch-all" precedence for
// selector, indexing, and other operator and delimiter tokens.
//
const (
	LowestPrec = 0;  // non-operators
	UnaryPrec = 7;
	HighestPrec = 8;
)

// Precedence returns the operator precedence of the binary
// operator op. If op is not a binary operator, the result
// is LowestPrecedence.
//
func (op Token) Precedence() int {
	switch op {
	case LOR:
		return 1;
	case LAND:
		return 2;
	case ARROW:
		return 3;
	case EQL, NEQ, LSS, LEQ, GTR, GEQ:
		return 4;
	case ADD, SUB, OR, XOR:
		return 5;
	case MUL, QUO, REM, SHL, SHR, AND, AND_NOT:
		return 6;
	}
	return LowestPrec;
}

var keywords map [string] Token;

func init() {
	keywords = make(map [string] Token);
	for i := keyword_beg + 1; i < keyword_end; i++ {
		keywords[tokens[i]] = i;
	}
}

// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
//
func Lookup(ident []byte) Token {
	// TODO Maps with []byte key are illegal because []byte does not
	//      support == . Should find a more efficient solution eventually.
	if tok, is_keyword := keywords[string(ident)]; is_keyword {
		return tok;
	}
	return IDENT;
}

// Predicates

// IsLiteral returns true for tokens corresponding to identifiers
// and basic type literals; returns false otherwise.
//
func (tok Token) IsLiteral() bool {
	return literal_beg < tok && tok < literal_end;
}

// IsOperator returns true for tokens corresponding to operators and
// delimiters; returns false otherwise.
//
func (tok Token) IsOperator() bool {
	return operator_beg < tok && tok < operator_end;
}

// IsKeyword returns true for tokens corresponding to keywords;
// returns false otherwise.
//
func (tok Token) IsKeyword() bool {
	return keyword_beg < tok && tok < keyword_end;
}

// Token source positions are represented by a Position value.
// A Position is valid if the line number is > 0.
//
type Position struct {
	Filename string;  // filename, if any
	Offset int;  // byte offset, starting at 0
	Line int;  // line number, starting at 1
	Column int;  // column number, starting at 1 (character count)
}

// Pos is an accessor method for anonymous Position fields.
// It returns its receiver.
//
func (pos *Position) Pos() Position {
	return *pos;
}

// IsValid returns true if the position is valid.
func (pos *Position) IsValid() bool {
	return pos.Line > 0
}

func (pos *Position) String() string {
	if pos != nil {
		s := pos.Filename;
		if pos.IsValid() {
			if s != "" {
				s += ":";
			}
			s += fmt.Sprintf("%d:%d", pos.Line, pos.Column);
		}
		if s != "" {
			return s;
		}
	}
	return "<unknown position>";
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin freebsd linux netbsd openbsd windows

package net

import (
	"syscall"
	"time"
)

var listenerBacklog = maxListenerBacklog()

// Generic POSIX socket creation.
func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
	s, err := sysSocket(f, t, p)
	if err != nil {
		return nil, err
	}

	if err = setDefaultSockopts(s, f, t, ipv6only); err != nil {
		closesocket(s)
		return nil, err
	}

	if ulsa != nil {
		// We provide a socket that listens to a wildcard
		// address with reusable UDP port when the given ulsa
		// is an appropriate UDP multicast address prefix.
		// This makes it possible for a single UDP listener
		// to join multiple different group addresses, for
		// multiple UDP listeners that listen on the same UDP
		// port to join the same group address.
		if ulsa, err = listenerSockaddr(s, f, ulsa, toAddr); err != nil {
			closesocket(s)
			return nil, err
		}
		if err = syscall.Bind(s, ulsa); err != nil {
			closesocket(s)
			return nil, err
		}
	}

	if fd, err = newFD(s, f, t, net); err != nil {
		closesocket(s)
		return nil, err
	}

	if ursa != nil {
		if !deadline.IsZero() {
			setWriteDeadline(fd, deadline)
		}
		if err = fd.connect(ursa); err != nil {
			closesocket(s)
			return nil, err
		}
		fd.isConnected = true
		if !deadline.IsZero() {
			setWriteDeadline(fd, time.Time{})
		}
	}

	lsa, _ := syscall.Getsockname(s)
	laddr := toAddr(lsa)
	rsa, _ := syscall.Getpeername(s)
	if rsa == nil {
		rsa = ursa
	}
	raddr := toAddr(rsa)
	fd.setAddr(laddr, raddr)
	return fd, nil
}
<commit_msg>net: avoid use of listener socket options on active open sockets<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin freebsd linux netbsd openbsd windows

package net

import (
	"syscall"
	"time"
)

var listenerBacklog = maxListenerBacklog()

// Generic POSIX socket creation.
func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
	s, err := sysSocket(f, t, p)
	if err != nil {
		return nil, err
	}

	if err = setDefaultSockopts(s, f, t, ipv6only); err != nil {
		closesocket(s)
		return nil, err
	}

	// This socket is used by a listener.
	if ulsa != nil && ursa == nil {
		// We provide a socket that listens to a wildcard
		// address with reusable UDP port when the given ulsa
		// is an appropriate UDP multicast address prefix.
		// This makes it possible for a single UDP listener
		// to join multiple different group addresses, for
		// multiple UDP listeners that listen on the same UDP
		// port to join the same group address.
		if ulsa, err = listenerSockaddr(s, f, ulsa, toAddr); err != nil {
			closesocket(s)
			return nil, err
		}
	}

	if ulsa != nil {
		if err = syscall.Bind(s, ulsa); err != nil {
			closesocket(s)
			return nil, err
		}
	}

	if fd, err = newFD(s, f, t, net); err != nil {
		closesocket(s)
		return nil, err
	}

	// This socket is used by a dialer.
	if ursa != nil {
		if !deadline.IsZero() {
			setWriteDeadline(fd, deadline)
		}
		if err = fd.connect(ursa); err != nil {
			closesocket(s)
			return nil, err
		}
		fd.isConnected = true
		if !deadline.IsZero() {
			setWriteDeadline(fd, time.Time{})
		}
	}

	lsa, _ := syscall.Getsockname(s)
	laddr := toAddr(lsa)
	rsa, _ := syscall.Getpeername(s)
	if rsa == nil {
		rsa = ursa
	}
	raddr := toAddr(rsa)
	fd.setAddr(laddr, raddr)
	return fd, nil
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin freebsd linux netbsd openbsd windows

package net

import (
	"os"
	"syscall"
	"time"
)

// A sockaddr represents a TCP, UDP, IP or Unix network endpoint
// address that can be converted into a syscall.Sockaddr.
type sockaddr interface {
	Addr

	// family returns the platform-dependent address family
	// identifier.
	family() int

	// isWildcard reports whether the address is a wildcard
	// address.
	isWildcard() bool

	// sockaddr returns the address converted into a syscall
	// sockaddr type that implements syscall.Sockaddr
	// interface. It returns a nil interface when the address is
	// nil.
	sockaddr(family int) (syscall.Sockaddr, error)

	// toAddr returns the address represented in sockaddr
	// interface. It returns a nil interface when the address is
	// nil.
	toAddr() sockaddr
}

// Generic POSIX socket creation.
func socket(net string, f, t, p int, ipv6only bool, laddr, raddr sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
	s, err := sysSocket(f, t, p)
	if err != nil {
		return nil, err
	}

	if err = setDefaultSockopts(s, f, t, ipv6only); err != nil {
		closesocket(s)
		return nil, err
	}

	if fd, err = newFD(s, f, t, net); err != nil {
		closesocket(s)
		return nil, err
	}

	// This function makes a network file descriptor for stream
	// and datagram dialers, stream and datagram listeners.
	//
	// For dialers, they will require either named or unnamed
	// sockets for their flights.  We can assume that it's just a
	// request from a dialer that wants a named socket when both
	// laddr and raddr are not nil.  A dialer will also require a
	// connection setup initiated socket when raddr is not nil.
	//
	// For listeners and some dialers on datagram networks, they
	// will only require named sockets.  So we can assume that
	// it's just for a listener or a datagram dialer when laddr is
	// not nil but raddr is nil.

	if laddr != nil && raddr == nil {
		switch t {
		case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
			if err := fd.listenStream(laddr, listenerBacklog, toAddr); err != nil {
				fd.Close()
				return nil, err
			}
			return fd, nil
		case syscall.SOCK_DGRAM:
			if err := fd.listenDatagram(laddr, toAddr); err != nil {
				fd.Close()
				return nil, err
			}
			return fd, nil
		}
	}
	if err := fd.dial(laddr, raddr, deadline, toAddr); err != nil {
		fd.Close()
		return nil, err
	}
	return fd, nil
}

func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) error {
	var err error
	var lsa syscall.Sockaddr
	if laddr != nil {
		if lsa, err = laddr.sockaddr(fd.family); err != nil {
			return err
		} else if lsa != nil {
			if err := syscall.Bind(fd.sysfd, lsa); err != nil {
				return os.NewSyscallError("bind", err)
			}
		}
	}
	if err := fd.init(); err != nil {
		return err
	}
	var rsa syscall.Sockaddr
	if raddr != nil {
		if rsa, err = raddr.sockaddr(fd.family); err != nil {
			return err
		} else if rsa != nil {
			if !deadline.IsZero() {
				fd.setWriteDeadline(deadline)
			}
			if err := fd.connect(lsa, rsa); err != nil {
				return err
			}
			fd.isConnected = true
			if !deadline.IsZero() {
				fd.setWriteDeadline(noDeadline)
			}
		}
	}
	lsa, _ = syscall.Getsockname(fd.sysfd)
	if rsa, _ = syscall.Getpeername(fd.sysfd); rsa != nil {
		fd.setAddr(toAddr(lsa), toAddr(rsa))
	} else {
		fd.setAddr(toAddr(lsa), raddr)
	}
	return nil
}

func (fd *netFD) listenStream(laddr sockaddr, backlog int, toAddr func(syscall.Sockaddr) Addr) error {
	if err := setDefaultListenerSockopts(fd.sysfd); err != nil {
		return err
	}
	if lsa, err := laddr.sockaddr(fd.family); err != nil {
		return err
	} else if lsa != nil {
		if err := syscall.Bind(fd.sysfd, lsa); err != nil {
			return os.NewSyscallError("bind", err)
		}
	}
	if err := syscall.Listen(fd.sysfd, backlog); err != nil {
		return os.NewSyscallError("listen", err)
	}
	if err := fd.init(); err != nil {
		return err
	}
	lsa, _ := syscall.Getsockname(fd.sysfd)
	fd.setAddr(toAddr(lsa), nil)
	return nil
}

func (fd *netFD) listenDatagram(laddr sockaddr, toAddr func(syscall.Sockaddr) Addr) error {
	switch addr := laddr.(type) {
	case *UDPAddr:
		// We provide a socket that listens to a wildcard
		// address with reusable UDP port when the given laddr
		// is an appropriate UDP multicast address prefix.
		// This makes it possible for a single UDP listener to
		// join multiple different group addresses, for
		// multiple UDP listeners that listen on the same UDP
		// port to join the same group address.
		if addr.IP != nil && addr.IP.IsMulticast() {
			if err := setDefaultMulticastSockopts(fd.sysfd); err != nil {
				return err
			}
			addr := *addr
			switch fd.family {
			case syscall.AF_INET:
				addr.IP = IPv4zero
			case syscall.AF_INET6:
				addr.IP = IPv6unspecified
			}
			laddr = &addr
		}
	}
	if lsa, err := laddr.sockaddr(fd.family); err != nil {
		return err
	} else if lsa != nil {
		if err := syscall.Bind(fd.sysfd, lsa); err != nil {
			return os.NewSyscallError("bind", err)
		}
	}
	if err := fd.init(); err != nil {
		return err
	}
	lsa, _ := syscall.Getsockname(fd.sysfd)
	fd.setAddr(toAddr(lsa), nil)
	return nil
}
<commit_msg>net: update doc on socket<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin freebsd linux netbsd openbsd windows

package net

import (
	"os"
	"syscall"
	"time"
)

// A sockaddr represents a TCP, UDP, IP or Unix network endpoint
// address that can be converted into a syscall.Sockaddr.
type sockaddr interface {
	Addr

	// family returns the platform-dependent address family
	// identifier.
	family() int

	// isWildcard reports whether the address is a wildcard
	// address.
	isWildcard() bool

	// sockaddr returns the address converted into a syscall
	// sockaddr type that implements syscall.Sockaddr
	// interface. It returns a nil interface when the address is
	// nil.
	sockaddr(family int) (syscall.Sockaddr, error)

	// toAddr returns the address represented in sockaddr
	// interface. It returns a nil interface when the address is
	// nil.
	toAddr() sockaddr
}

// socket returns a network file descriptor that is ready for
// asynchronous I/O using the network poller.
func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
	s, err := sysSocket(family, sotype, proto)
	if err != nil {
		return nil, err
	}
	if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
		closesocket(s)
		return nil, err
	}
	if fd, err = newFD(s, family, sotype, net); err != nil {
		closesocket(s)
		return nil, err
	}

	// This function makes a network file descriptor for the
	// following applications:
	//
	// - An endpoint holder that opens a passive stream
	//   connenction, known as a stream listener
	//
	// - An endpoint holder that opens a destination-unspecific
	//   datagram connection, known as a datagram listener
	//
	// - An endpoint holder that opens an active stream or a
	//   destination-specific datagram connection, known as a
	//   dialer
	//
	// - An endpoint holder that opens the other connection, such
	//   as talking to the protocol stack inside the kernel
	//
	// For stream and datagram listeners, they will only require
	// named sockets, so we can assume that it's just a request
	// from stream or datagram listeners when laddr is not nil but
	// raddr is nil. Otherwise we assume it's just for dialers or
	// the other connection holders.

	if laddr != nil && raddr == nil {
		switch sotype {
		case syscall.SOCK_STREAM, syscall.SOCK_SEQPACKET:
			if err := fd.listenStream(laddr, listenerBacklog, toAddr); err != nil {
				fd.Close()
				return nil, err
			}
			return fd, nil
		case syscall.SOCK_DGRAM:
			if err := fd.listenDatagram(laddr, toAddr); err != nil {
				fd.Close()
				return nil, err
			}
			return fd, nil
		}
	}
	if err := fd.dial(laddr, raddr, deadline, toAddr); err != nil {
		fd.Close()
		return nil, err
	}
	return fd, nil
}

func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) error {
	var err error
	var lsa syscall.Sockaddr
	if laddr != nil {
		if lsa, err = laddr.sockaddr(fd.family); err != nil {
			return err
		} else if lsa != nil {
			if err := syscall.Bind(fd.sysfd, lsa); err != nil {
				return os.NewSyscallError("bind", err)
			}
		}
	}
	if err := fd.init(); err != nil {
		return err
	}
	var rsa syscall.Sockaddr
	if raddr != nil {
		if rsa, err = raddr.sockaddr(fd.family); err != nil {
			return err
		} else if rsa != nil {
			if !deadline.IsZero() {
				fd.setWriteDeadline(deadline)
			}
			if err := fd.connect(lsa, rsa); err != nil {
				return err
			}
			fd.isConnected = true
			if !deadline.IsZero() {
				fd.setWriteDeadline(noDeadline)
			}
		}
	}
	lsa, _ = syscall.Getsockname(fd.sysfd)
	if rsa, _ = syscall.Getpeername(fd.sysfd); rsa != nil {
		fd.setAddr(toAddr(lsa), toAddr(rsa))
	} else {
		fd.setAddr(toAddr(lsa), raddr)
	}
	return nil
}

func (fd *netFD) listenStream(laddr sockaddr, backlog int, toAddr func(syscall.Sockaddr) Addr) error {
	if err := setDefaultListenerSockopts(fd.sysfd); err != nil {
		return err
	}
	if lsa, err := laddr.sockaddr(fd.family); err != nil {
		return err
	} else if lsa != nil {
		if err := syscall.Bind(fd.sysfd, lsa); err != nil {
			return os.NewSyscallError("bind", err)
		}
	}
	if err := syscall.Listen(fd.sysfd, backlog); err != nil {
		return os.NewSyscallError("listen", err)
	}
	if err := fd.init(); err != nil {
		return err
	}
	lsa, _ := syscall.Getsockname(fd.sysfd)
	fd.setAddr(toAddr(lsa), nil)
	return nil
}

func (fd *netFD) listenDatagram(laddr sockaddr, toAddr func(syscall.Sockaddr) Addr) error {
	switch addr := laddr.(type) {
	case *UDPAddr:
		// We provide a socket that listens to a wildcard
		// address with reusable UDP port when the given laddr
		// is an appropriate UDP multicast address prefix.
		// This makes it possible for a single UDP listener to
		// join multiple different group addresses, for
		// multiple UDP listeners that listen on the same UDP
		// port to join the same group address.
		if addr.IP != nil && addr.IP.IsMulticast() {
			if err := setDefaultMulticastSockopts(fd.sysfd); err != nil {
				return err
			}
			addr := *addr
			switch fd.family {
			case syscall.AF_INET:
				addr.IP = IPv4zero
			case syscall.AF_INET6:
				addr.IP = IPv6unspecified
			}
			laddr = &addr
		}
	}
	if lsa, err := laddr.sockaddr(fd.family); err != nil {
		return err
	} else if lsa != nil {
		if err := syscall.Bind(fd.sysfd, lsa); err != nil {
			return os.NewSyscallError("bind", err)
		}
	}
	if err := fd.init(); err != nil {
		return err
	}
	lsa, _ := syscall.Getsockname(fd.sysfd)
	fd.setAddr(toAddr(lsa), nil)
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Windows environment variables.

package os

import (
	"syscall"
	"utf16"
	"unsafe"
)

// ENOENV is the Error indicating that an environment variable does not exist.
var ENOENV = NewError("no such environment variable")

// Getenverror retrieves the value of the environment variable named by the key.
// It returns the value and an error, if any.
func Getenverror(key string) (value string, err Error) {
	b := make([]uint16, 100)
	n, e := syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
	if n == 0 && e == syscall.ERROR_ENVVAR_NOT_FOUND {
		return "", ENOENV
	}
	if n > uint32(len(b)) {
		b = make([]uint16, n)
		n, e = syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
		if n > uint32(len(b)) {
			n = 0
		}
	}
	if n == 0 {
		return "", NewSyscallError("GetEnvironmentVariable", e)
	}
	return string(utf16.Decode(b[0:n])), nil
}

// Getenv retrieves the value of the environment variable named by the key.
// It returns the value, which will be empty if the variable is not present.
func Getenv(key string) string {
	v, _ := Getenverror(key)
	return v
}

// Setenv sets the value of the environment variable named by the key.
// It returns an Error, if any.
func Setenv(key, value string) Error {
	var v *uint16
	if len(value) > 0 {
		v = syscall.StringToUTF16Ptr(value)
	}
	ok, e := syscall.SetEnvironmentVariable(syscall.StringToUTF16Ptr(key), v)
	if !ok {
		return NewSyscallError("SetEnvironmentVariable", e)
	}
	return nil
}

// Clearenv deletes all environment variables.
func Clearenv() {
	for _, s := range Environ() {
		for j := 0; j < len(s); j++ {
			if s[j] == '=' {
				Setenv(s[0:j], "")
			}
		}
	}
}

// Environ returns an array of strings representing the environment,
// in the form "key=value".
func Environ() []string {
	s, e := syscall.GetEnvironmentStrings()
	if e != 0 {
		return nil
	}
	defer syscall.FreeEnvironmentStrings(s)
	r := make([]string, 0, 50) // Empty with room to grow.
	for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
		if p[i] == 0 {
			// empty string marks the end
			if i <= from {
				break
			}
			// skip anything that starts with '='
			if p[from] != '=' {
				if len(r) == cap(r) {
					nr := make([]string, len(r), 2*len(r))
					for k := 0; k < len(r); k++ {
						nr[k] = r[k]
					}
					r = nr
				}
				r = r[0 : len(r)+1]
				r[len(r)-1] = string(utf16.Decode(p[from:i]))
			}
			from = i + 1
		}
	}
	return r
}

// TempDir returns the default directory to use for temporary files.
func TempDir() string {
	const pathSep = '\\'
	dirw := make([]uint16, syscall.MAX_PATH)
	n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
	if n > uint32(len(dirw)) {
		dirw = make([]uint16, n)
		n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
		if n > uint32(len(dirw)) {
			n = 0
		}
	}
	if n > 0 && dirw[n-1] == pathSep {
		n--
	}
	return string(utf16.Decode(dirw[0:n]))
}
<commit_msg>os: preserve "=C:" like env variables in env block on windows and bug fix in Clearenv()<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Windows environment variables.

package os

import (
	"syscall"
	"utf16"
	"unsafe"
)

// ENOENV is the Error indicating that an environment variable does not exist.
var ENOENV = NewError("no such environment variable")

// Getenverror retrieves the value of the environment variable named by the key.
// It returns the value and an error, if any.
func Getenverror(key string) (value string, err Error) {
	b := make([]uint16, 100)
	n, e := syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
	if n == 0 && e == syscall.ERROR_ENVVAR_NOT_FOUND {
		return "", ENOENV
	}
	if n > uint32(len(b)) {
		b = make([]uint16, n)
		n, e = syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
		if n > uint32(len(b)) {
			n = 0
		}
	}
	if n == 0 {
		return "", NewSyscallError("GetEnvironmentVariable", e)
	}
	return string(utf16.Decode(b[0:n])), nil
}

// Getenv retrieves the value of the environment variable named by the key.
// It returns the value, which will be empty if the variable is not present.
func Getenv(key string) string {
	v, _ := Getenverror(key)
	return v
}

// Setenv sets the value of the environment variable named by the key.
// It returns an Error, if any.
func Setenv(key, value string) Error {
	var v *uint16
	if len(value) > 0 {
		v = syscall.StringToUTF16Ptr(value)
	}
	ok, e := syscall.SetEnvironmentVariable(syscall.StringToUTF16Ptr(key), v)
	if !ok {
		return NewSyscallError("SetEnvironmentVariable", e)
	}
	return nil
}

// Clearenv deletes all environment variables.
func Clearenv() {
	for _, s := range Environ() {
		// Environment variables can begin with =
		// so start looking for the separator = at j=1.
		// http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
		for j := 1; j < len(s); j++ {
			if s[j] == '=' {
				Setenv(s[0:j], "")
				break
			}
		}
	}
}

// Environ returns an array of strings representing the environment,
// in the form "key=value".
func Environ() []string {
	s, e := syscall.GetEnvironmentStrings()
	if e != 0 {
		return nil
	}
	defer syscall.FreeEnvironmentStrings(s)
	r := make([]string, 0, 50) // Empty with room to grow.
	for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
		if p[i] == 0 {
			// empty string marks the end
			if i <= from {
				break
			}
			if len(r) == cap(r) {
				nr := make([]string, len(r), 2*len(r))
				for k := 0; k < len(r); k++ {
					nr[k] = r[k]
				}
				r = nr
			}
			r = r[0 : len(r)+1]
			r[len(r)-1] = string(utf16.Decode(p[from:i]))
			from = i + 1
		}
	}
	return r
}

// TempDir returns the default directory to use for temporary files.
func TempDir() string {
	const pathSep = '\\'
	dirw := make([]uint16, syscall.MAX_PATH)
	n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
	if n > uint32(len(dirw)) {
		dirw = make([]uint16, n)
		n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
		if n > uint32(len(dirw)) {
			n = 0
		}
	}
	if n > 0 && dirw[n-1] == pathSep {
		n--
	}
	return string(utf16.Decode(dirw[0:n]))
}
<|endoftext|>


<commit_before>package dnsmasq

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/storage/filesystem"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/subprocess"
	"github.com/lxc/lxd/shared/version"
)

const staticAllocationDeviceSeparator = "."

// DHCPAllocation represents an IP allocation from dnsmasq.
type DHCPAllocation struct {
	IP     net.IP
	Name   string
	MAC    net.HardwareAddr
	Static bool
}

// ConfigMutex used to coordinate access to the dnsmasq config files.
var ConfigMutex sync.Mutex

// UpdateStaticEntry writes a single dhcp-host line for a network/instance combination.
func UpdateStaticEntry(network string, projectName string, instanceName string, deviceName string, netConfig map[string]string, hwaddr string, ipv4Address string, ipv6Address string) error {
	hwaddr = strings.ToLower(hwaddr)
	line := hwaddr

	// Generate the dhcp-host line
	if ipv4Address != "" {
		line += fmt.Sprintf(",%s", ipv4Address)
	}

	if ipv6Address != "" {
		line += fmt.Sprintf(",[%s]", ipv6Address)
	}

	if netConfig["dns.mode"] == "" || netConfig["dns.mode"] == "managed" {
		line += fmt.Sprintf(",%s", project.DNS(projectName, instanceName))
	}

	if line == hwaddr {
		return nil
	}

	deviceStaticFileName := StaticAllocationFileName(projectName, instanceName, deviceName)
	err := ioutil.WriteFile(shared.VarPath("networks", network, "dnsmasq.hosts", deviceStaticFileName), []byte(line+"\n"), 0644)
	if err != nil {
		return err
	}

	return nil
}

// RemoveStaticEntry removes a single dhcp-host line for a network/instance combination.
func RemoveStaticEntry(network string, projectName string, instanceName string, deviceName string) error {
	deviceStaticFileName := StaticAllocationFileName(projectName, instanceName, deviceName)
	err := os.Remove(shared.VarPath("networks", network, "dnsmasq.hosts", deviceStaticFileName))
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	return nil
}

// Kill kills dnsmasq for a particular network (or optionally reloads it).
func Kill(name string, reload bool) error {
	pidPath := shared.VarPath("networks", name, "dnsmasq.pid")

	// If the pid file doesn't exist, there is no process to kill.
	if !shared.PathExists(pidPath) {
		return nil
	}

	// Import saved subprocess details
	p, err := subprocess.ImportProcess(pidPath)
	if err != nil {
		return fmt.Errorf("Could not read pid file: %s", err)
	}

	if reload {
		err = p.Reload()
		if err != nil && err != subprocess.ErrNotRunning {
			return fmt.Errorf("Could not reload dnsmasq: %s", err)
		}

		return nil
	}

	err = p.Stop()
	if err != nil && err != subprocess.ErrNotRunning {
		return fmt.Errorf("Unable to kill dnsmasq: %s", err)
	}

	time.Sleep(100 * time.Millisecond) // Give OS time to release sockets.

	return nil
}

// GetVersion returns the version of dnsmasq.
func GetVersion() (*version.DottedVersion, error) {
	output, err := shared.RunCommandCLocale("dnsmasq", "--version")
	if err != nil {
		return nil, fmt.Errorf("Failed to check dnsmasq version: %v", err)
	}

	lines := strings.Split(string(output), " ")
	return version.Parse(lines[2])
}

// DHCPStaticAllocation retrieves the dnsmasq statically allocated MAC and IPs for an instance.
// Returns MAC, IPv4 and IPv6 DHCPAllocation structs respectively.
// The projectName, instanceName, and deviceName are used to generate the entryFileName. If the entryFileName
// argument is provided, then projectName, instanceName, and deviceName are ignored.
func DHCPStaticAllocation(network, projectName, instanceName, deviceName, entryFileName string) (net.HardwareAddr, DHCPAllocation, DHCPAllocation, error) {
	var IPv4, IPv6 DHCPAllocation
	var mac net.HardwareAddr

	if entryFileName == "" {
		entryFileName = StaticAllocationFileName(projectName, instanceName, deviceName)
	}

	file, err := os.Open(shared.VarPath("networks", network, "dnsmasq.hosts", entryFileName))
	if err != nil {
		return nil, IPv4, IPv6, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		fields := strings.SplitN(scanner.Text(), ",", -1)
		for _, field := range fields {
			// Check if field is IPv4 or IPv6 address.
			if strings.Count(field, ".") == 3 {
				IP := net.ParseIP(field)
				if IP.To4() == nil {
					return nil, IPv4, IPv6, fmt.Errorf("Error parsing IP address %q", field)
				}
				IPv4 = DHCPAllocation{Name: instanceName, Static: true, IP: IP.To4(), MAC: mac}

			} else if strings.HasPrefix(field, "[") && strings.HasSuffix(field, "]") {
				IP := net.ParseIP(field[1 : len(field)-1])
				if IP == nil {
					return nil, IPv4, IPv6, fmt.Errorf("Error parsing IP address %q", field)
				}
				IPv6 = DHCPAllocation{Name: instanceName, Static: true, IP: IP, MAC: mac}
			} else if strings.Count(field, ":") == 5 {
				// This field is expected to come first, so that mac variable can be used with
				// populating the DHCPAllocation structs too.
				mac, err = net.ParseMAC(field)
				if err != nil {
					return nil, IPv4, IPv6, fmt.Errorf("Error parsing MAC address %q", field)
				}
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, IPv4, IPv6, err
	}

	return mac, IPv4, IPv6, nil
}

// DHCPAllAllocations returns a map of IPs currently allocated (statically and dynamically)
// in dnsmasq for a specific network. The returned map is keyed by a 16 byte array representing
// the net.IP format. The value of each map item is a DHCPAllocation struct containing at least
// whether the allocation was static or dynamic and optionally instance name or MAC address.
// MAC addresses are only included for dynamic IPv4 allocations (where name is not reliable).
// Static allocations are not overridden by dynamic allocations, allowing for instance name to be
// included for static IPv6 allocations. IPv6 addresses that are dynamically assigned cannot be
// reliably linked to instances using either name or MAC because dnsmasq does not record the MAC
// address for these records, and the recorded host name can be set by the instance if the dns.mode
// for the network is set to "dynamic" and so cannot be trusted, so in this case we do not return
// any identifying info.
func DHCPAllAllocations(network string) (map[[4]byte]DHCPAllocation, map[[16]byte]DHCPAllocation, error) {
	IPv4s := make(map[[4]byte]DHCPAllocation)
	IPv6s := make(map[[16]byte]DHCPAllocation)

	// First read all statically allocated IPs.
	files, err := ioutil.ReadDir(shared.VarPath("networks", network, "dnsmasq.hosts"))
	if err != nil && os.IsNotExist(err) {
		return nil, nil, err
	}

	for _, entry := range files {
		_, IPv4, IPv6, err := DHCPStaticAllocation(network, "", "", "", entry.Name())
		if err != nil {
			return nil, nil, err
		}

		if IPv4.IP != nil {
			var IPKey [4]byte
			copy(IPKey[:], IPv4.IP.To4())
			IPv4s[IPKey] = IPv4
		}

		if IPv6.IP != nil {
			var IPKey [16]byte
			copy(IPKey[:], IPv6.IP.To16())
			IPv6s[IPKey] = IPv6
		}
	}

	// Next read all dynamic allocated IPs.
	file, err := os.Open(shared.VarPath("networks", network, "dnsmasq.leases"))
	if err != nil {
		return nil, nil, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		fields := strings.Fields(scanner.Text())
		if len(fields) == 5 {
			IP := net.ParseIP(fields[2])
			if IP == nil {
				return nil, nil, fmt.Errorf("Error parsing IP address: %v", fields[2])
			}

			// Handle IPv6 addresses.
			if IP.To4() == nil {
				var IPKey [16]byte
				copy(IPKey[:], IP.To16())

				// Don't replace IPs from static config as more reliable.
				if IPv6s[IPKey].Name != "" {
					continue
				}

				IPv6s[IPKey] = DHCPAllocation{
					Static: false,
					IP:     IP.To16(),
				}
			} else {
				// MAC only available in IPv4 leases.
				MAC, err := net.ParseMAC(fields[1])
				if err != nil {
					return nil, nil, err
				}

				var IPKey [4]byte
				copy(IPKey[:], IP.To4())

				// Don't replace IPs from static config as more reliable.
				if IPv4s[IPKey].Name != "" {
					continue
				}

				IPv4s[IPKey] = DHCPAllocation{
					MAC:    MAC,
					Static: false,
					IP:     IP.To4(),
				}
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, nil, err
	}

	return IPv4s, IPv6s, nil
}

// StaticAllocationFileName returns the file name to use for a dnsmasq instance device static allocation.
func StaticAllocationFileName(projectName string, instanceName string, deviceName string) string {
	escapedDeviceName := filesystem.PathNameEncode(deviceName)

	return strings.Join([]string{project.Instance(projectName, instanceName), escapedDeviceName}, staticAllocationDeviceSeparator)
}
<commit_msg>lxd/dnsmasq: Removes Name and Static field and replaces with StaticFileName field<commit_after>package dnsmasq

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/storage/filesystem"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/subprocess"
	"github.com/lxc/lxd/shared/version"
)

const staticAllocationDeviceSeparator = "."

// DHCPAllocation represents an IP allocation from dnsmasq.
type DHCPAllocation struct {
	IP             net.IP
	StaticFileName string
	MAC            net.HardwareAddr
}

// ConfigMutex used to coordinate access to the dnsmasq config files.
var ConfigMutex sync.Mutex

// UpdateStaticEntry writes a single dhcp-host line for a network/instance combination.
func UpdateStaticEntry(network string, projectName string, instanceName string, deviceName string, netConfig map[string]string, hwaddr string, ipv4Address string, ipv6Address string) error {
	hwaddr = strings.ToLower(hwaddr)
	line := hwaddr

	// Generate the dhcp-host line
	if ipv4Address != "" {
		line += fmt.Sprintf(",%s", ipv4Address)
	}

	if ipv6Address != "" {
		line += fmt.Sprintf(",[%s]", ipv6Address)
	}

	if netConfig["dns.mode"] == "" || netConfig["dns.mode"] == "managed" {
		line += fmt.Sprintf(",%s", project.DNS(projectName, instanceName))
	}

	if line == hwaddr {
		return nil
	}

	deviceStaticFileName := StaticAllocationFileName(projectName, instanceName, deviceName)
	err := ioutil.WriteFile(shared.VarPath("networks", network, "dnsmasq.hosts", deviceStaticFileName), []byte(line+"\n"), 0644)
	if err != nil {
		return err
	}

	return nil
}

// RemoveStaticEntry removes a single dhcp-host line for a network/instance combination.
func RemoveStaticEntry(network string, projectName string, instanceName string, deviceName string) error {
	deviceStaticFileName := StaticAllocationFileName(projectName, instanceName, deviceName)
	err := os.Remove(shared.VarPath("networks", network, "dnsmasq.hosts", deviceStaticFileName))
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	return nil
}

// Kill kills dnsmasq for a particular network (or optionally reloads it).
func Kill(name string, reload bool) error {
	pidPath := shared.VarPath("networks", name, "dnsmasq.pid")

	// If the pid file doesn't exist, there is no process to kill.
	if !shared.PathExists(pidPath) {
		return nil
	}

	// Import saved subprocess details
	p, err := subprocess.ImportProcess(pidPath)
	if err != nil {
		return fmt.Errorf("Could not read pid file: %s", err)
	}

	if reload {
		err = p.Reload()
		if err != nil && err != subprocess.ErrNotRunning {
			return fmt.Errorf("Could not reload dnsmasq: %s", err)
		}

		return nil
	}

	err = p.Stop()
	if err != nil && err != subprocess.ErrNotRunning {
		return fmt.Errorf("Unable to kill dnsmasq: %s", err)
	}

	time.Sleep(100 * time.Millisecond) // Give OS time to release sockets.

	return nil
}

// GetVersion returns the version of dnsmasq.
func GetVersion() (*version.DottedVersion, error) {
	output, err := shared.RunCommandCLocale("dnsmasq", "--version")
	if err != nil {
		return nil, fmt.Errorf("Failed to check dnsmasq version: %v", err)
	}

	lines := strings.Split(string(output), " ")
	return version.Parse(lines[2])
}

// DHCPStaticAllocation retrieves the dnsmasq statically allocated MAC and IPs for an instance.
// Returns MAC, IPv4 and IPv6 DHCPAllocation structs respectively.
// The projectName, instanceName, and deviceName are used to generate the entryFileName. If the entryFileName
// argument is provided, then projectName, instanceName, and deviceName are ignored.
func DHCPStaticAllocation(network, projectName, instanceName, deviceName, entryFileName string) (net.HardwareAddr, DHCPAllocation, DHCPAllocation, error) {
	var IPv4, IPv6 DHCPAllocation
	var mac net.HardwareAddr

	if entryFileName == "" {
		entryFileName = StaticAllocationFileName(projectName, instanceName, deviceName)
	}

	file, err := os.Open(shared.VarPath("networks", network, "dnsmasq.hosts", entryFileName))
	if err != nil {
		return nil, IPv4, IPv6, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		fields := strings.SplitN(scanner.Text(), ",", -1)
		for _, field := range fields {
			// Check if field is IPv4 or IPv6 address.
			if strings.Count(field, ".") == 3 {
				IP := net.ParseIP(field)
				if IP.To4() == nil {
					return nil, IPv4, IPv6, fmt.Errorf("Error parsing IP address %q", field)
				}
				IPv4 = DHCPAllocation{Name: instanceName, Static: true, IP: IP.To4(), MAC: mac}

			} else if strings.HasPrefix(field, "[") && strings.HasSuffix(field, "]") {
				IP := net.ParseIP(field[1 : len(field)-1])
				if IP == nil {
					return nil, IPv4, IPv6, fmt.Errorf("Error parsing IP address %q", field)
				}
				IPv6 = DHCPAllocation{Name: instanceName, Static: true, IP: IP, MAC: mac}
			} else if strings.Count(field, ":") == 5 {
				// This field is expected to come first, so that mac variable can be used with
				// populating the DHCPAllocation structs too.
				mac, err = net.ParseMAC(field)
				if err != nil {
					return nil, IPv4, IPv6, fmt.Errorf("Error parsing MAC address %q", field)
				}
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, IPv4, IPv6, err
	}

	return mac, IPv4, IPv6, nil
}

// DHCPAllAllocations returns a map of IPs currently allocated (statically and dynamically)
// in dnsmasq for a specific network. The returned map is keyed by a 16 byte array representing
// the net.IP format. The value of each map item is a DHCPAllocation struct containing at least
// whether the allocation was static or dynamic and optionally instance name or MAC address.
// MAC addresses are only included for dynamic IPv4 allocations (where name is not reliable).
// Static allocations are not overridden by dynamic allocations, allowing for instance name to be
// included for static IPv6 allocations. IPv6 addresses that are dynamically assigned cannot be
// reliably linked to instances using either name or MAC because dnsmasq does not record the MAC
// address for these records, and the recorded host name can be set by the instance if the dns.mode
// for the network is set to "dynamic" and so cannot be trusted, so in this case we do not return
// any identifying info.
func DHCPAllAllocations(network string) (map[[4]byte]DHCPAllocation, map[[16]byte]DHCPAllocation, error) {
	IPv4s := make(map[[4]byte]DHCPAllocation)
	IPv6s := make(map[[16]byte]DHCPAllocation)

	// First read all statically allocated IPs.
	files, err := ioutil.ReadDir(shared.VarPath("networks", network, "dnsmasq.hosts"))
	if err != nil && os.IsNotExist(err) {
		return nil, nil, err
	}

	for _, entry := range files {
		_, IPv4, IPv6, err := DHCPStaticAllocation(network, "", "", "", entry.Name())
		if err != nil {
			return nil, nil, err
		}

		if IPv4.IP != nil {
			var IPKey [4]byte
			copy(IPKey[:], IPv4.IP.To4())
			IPv4s[IPKey] = IPv4
		}

		if IPv6.IP != nil {
			var IPKey [16]byte
			copy(IPKey[:], IPv6.IP.To16())
			IPv6s[IPKey] = IPv6
		}
	}

	// Next read all dynamic allocated IPs.
	file, err := os.Open(shared.VarPath("networks", network, "dnsmasq.leases"))
	if err != nil {
		return nil, nil, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		fields := strings.Fields(scanner.Text())
		if len(fields) == 5 {
			IP := net.ParseIP(fields[2])
			if IP == nil {
				return nil, nil, fmt.Errorf("Error parsing IP address: %v", fields[2])
			}

			// Handle IPv6 addresses.
			if IP.To4() == nil {
				var IPKey [16]byte
				copy(IPKey[:], IP.To16())

				// Don't replace IPs from static config as more reliable.
				if IPv6s[IPKey].Name != "" {
					continue
				}

				IPv6s[IPKey] = DHCPAllocation{
					Static: false,
					IP:     IP.To16(),
				}
			} else {
				// MAC only available in IPv4 leases.
				MAC, err := net.ParseMAC(fields[1])
				if err != nil {
					return nil, nil, err
				}

				var IPKey [4]byte
				copy(IPKey[:], IP.To4())

				// Don't replace IPs from static config as more reliable.
				if IPv4s[IPKey].Name != "" {
					continue
				}

				IPv4s[IPKey] = DHCPAllocation{
					MAC:    MAC,
					Static: false,
					IP:     IP.To4(),
				}
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, nil, err
	}

	return IPv4s, IPv6s, nil
}

// StaticAllocationFileName returns the file name to use for a dnsmasq instance device static allocation.
func StaticAllocationFileName(projectName string, instanceName string, deviceName string) string {
	escapedDeviceName := filesystem.PathNameEncode(deviceName)

	return strings.Join([]string{project.Instance(projectName, instanceName), escapedDeviceName}, staticAllocationDeviceSeparator)
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package time_test

import (
	"testing"
	. "time"
)

func TestTicker(t *testing.T) {
	const Count = 10
	Delta := 100 * Millisecond
	if testing.Short() {
		Delta = 20 * Millisecond
	}
	ticker := NewTicker(Delta)
	t0 := Now()
	for i := 0; i < Count; i++ {
		<-ticker.C
	}
	ticker.Stop()
	t1 := Now()
	dt := t1.Sub(t0)
	target := Delta * Count
	slop := target * 2 / 10
	if dt < target-slop || dt > target+slop {
		t.Fatalf("%d %s ticks took %s, expected [%s,%s]", Count, Delta, dt, target-slop, target+slop)
	}
	// Now test that the ticker stopped
	Sleep(2 * Delta)
	select {
	case <-ticker.C:
		t.Fatal("Ticker did not shut down")
	default:
		// ok
	}
}

// Test that a bug tearing down a ticker has been fixed.  This routine should not deadlock.
func TestTeardown(t *testing.T) {
	Delta := 100 * Millisecond
	if testing.Short() {
		Delta = 20 * Millisecond
	}
	for i := 0; i < 3; i++ {
		ticker := NewTicker(Delta)
		<-ticker.C
		ticker.Stop()
	}
}

func BenchmarkTicker(b *testing.B) {
	ticker := NewTicker(1)
	b.ResetTimer()
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		<-ticker.C
	}
	b.StopTimer()
	ticker.Stop()
}
<commit_msg>time: run full TestTicker test even during short tests<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package time_test

import (
	"testing"
	. "time"
)

func TestTicker(t *testing.T) {
	const Count = 10
	Delta := 100 * Millisecond
	ticker := NewTicker(Delta)
	t0 := Now()
	for i := 0; i < Count; i++ {
		<-ticker.C
	}
	ticker.Stop()
	t1 := Now()
	dt := t1.Sub(t0)
	target := Delta * Count
	slop := target * 2 / 10
	if dt < target-slop || dt > target+slop {
		t.Fatalf("%d %s ticks took %s, expected [%s,%s]", Count, Delta, dt, target-slop, target+slop)
	}
	// Now test that the ticker stopped
	Sleep(2 * Delta)
	select {
	case <-ticker.C:
		t.Fatal("Ticker did not shut down")
	default:
		// ok
	}
}

// Test that a bug tearing down a ticker has been fixed.  This routine should not deadlock.
func TestTeardown(t *testing.T) {
	Delta := 100 * Millisecond
	if testing.Short() {
		Delta = 20 * Millisecond
	}
	for i := 0; i < 3; i++ {
		ticker := NewTicker(Delta)
		<-ticker.C
		ticker.Stop()
	}
}

func BenchmarkTicker(b *testing.B) {
	ticker := NewTicker(1)
	b.ResetTimer()
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		<-ticker.C
	}
	b.StopTimer()
	ticker.Stop()
}
<|endoftext|>


<commit_before>package mcmap

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/kch42/gonbt/nbt"
	"time"
)

const (
	_ = iota
	compressGZip
	compressZlib
)

type preChunk struct {
	ts          time.Time
	data        []byte
	compression byte
}

var (
	UnknownCompression = errors.New("Unknown chunk compression")
)

func halfbyte(b []byte, i int) byte {
	if i%2 == 0 {
		return b[i/2] & 0x0f
	}
	return (b[i/2] >> 4) & 0x0f
}

func setHalfbyte(b []byte, i int, v byte) {
	v &= 0xf
	if i%2 == 0 {
		b[i/2] |= v
	} else {
		b[i/2] |= v << 4
	}
}

func extractCoord(tc nbt.TagCompound) (x, y, z int, err error) {
	var _x, _y, _z int32
	if _x, err = tc.GetInt("x"); err != nil {
		return
	}
	if _y, err = tc.GetInt("y"); err != nil {
		return
	}
	_z, err = tc.GetInt("z")
	x, y, z = int(_x), int(_y), int(_z)
	return
}

func (pc *preChunk) getLevelTag() (nbt.TagCompound, error) {
	r := bytes.NewReader(pc.data)

	var root nbt.Tag
	var err error
	switch pc.compression {
	case compressGZip:
		root, _, err = nbt.ReadGzipdNamedTag(r)
	case compressZlib:
		root, _, err = nbt.ReadZlibdNamedTag(r)
	default:
		err = UnknownCompression
	}

	if err != nil {
		return nil, err
	}

	if root.Type != nbt.TAG_Compound {
		return nil, errors.New("Root tag is not a TAG_Compound")
	}

	lvl, err := root.Payload.(nbt.TagCompound).GetCompound("Level")
	if err != nil {
		return nil, fmt.Errorf("Could not read Level tag: %s", err)
	}

	return lvl, nil
}

func (pc *preChunk) toChunk(reg *Region) (*Chunk, error) {
	c := Chunk{ts: pc.ts, reg: reg}

	lvl, err := pc.getLevelTag()
	if err != nil {
		return nil, err
	}

	c.x, err = lvl.GetInt("xPos")
	if err != nil {
		return nil, fmt.Errorf("Could not read xPos tag: %s", err)
	}
	c.z, err = lvl.GetInt("zPos")
	if err != nil {
		return nil, fmt.Errorf("Could not read zPos tag: %s", err)
	}

	c.lastUpdate, err = lvl.GetLong("LastUpdate")
	if err != nil {
		return nil, fmt.Errorf("Could not read LastUpdate tag: %s", err)
	}

	populated, err := lvl.GetByte("TerrainPopulated")
	switch err {
	case nil:
	case nbt.NotFound:
		populated = 1
	default:
		return nil, fmt.Errorf("Could not read TerrainPopulated tag: %s", err)
	}
	c.populated = (populated == 1)

	c.inhabitedTime, err = lvl.GetLong("InhabitedTime")
	switch err {
	case nil:
	case nbt.NotFound:
		c.inhabitedTime = 0
	default:
		return nil, fmt.Errorf("Could not read InhabitatedTime tag: %s", err)
	}

	c.biomes = make([]Biome, ChunkRectXZ)
	biomes, err := lvl.GetByteArray("Biomes")
	switch err {
	case nil:
		for i, bio := range biomes {
			c.biomes[i] = Biome(bio)
		}
	case nbt.NotFound:
		for i := 0; i < ChunkRectXZ; i++ {
			c.biomes[i] = BioUncalculated
		}
	default:
		return nil, fmt.Errorf("Could not read Biomes tag: %s", err)
	}

	c.heightMap, err = lvl.GetIntArray("HeightMap")
	if err != nil {
		return nil, fmt.Errorf("Could not read HeightMap tag: %s", err)
	}

	ents, err := lvl.GetList("Entities")
	if err != nil {
		return nil, fmt.Errorf("Could not read Entities tag: %s", err)
	}
	if ents.Type != nbt.TAG_Compound {
		c.Entities = []nbt.TagCompound{}
	} else {
		c.Entities = make([]nbt.TagCompound, len(ents.Elems))
		for i, ent := range ents.Elems {
			c.Entities[i] = ent.(nbt.TagCompound)
		}
	}

	sections, err := lvl.GetList("Sections")
	if (err != nil) || (sections.Type != nbt.TAG_Compound) {
		return nil, fmt.Errorf("Could not read Section tag: %s", err)
	}

	c.blocks = make([]Block, ChunkSize)
	for _, _section := range sections.Elems {
		section := _section.(nbt.TagCompound)

		y, err := section.GetByte("Y")
		if err != nil {
			return nil, fmt.Errorf("Could not read Section -> Y tag: %s", err)
		}
		off := int(y) * chunkSectionSize

		blocks, err := section.GetByteArray("Blocks")
		if err != nil {
			return nil, fmt.Errorf("Could not read Section -> Blocks tag: %s", err)
		}
		blocksAdd := make([]byte, chunkSectionSize)
		add, err := section.GetByteArray("Add")
		switch err {
		case nil:
			for i := 0; i < chunkSectionSize; i++ {
				blocksAdd[i] = halfbyte(add, i)
			}
		case nbt.NotFound:
		default:
			return nil, fmt.Errorf("Could not read Section -> Add tag: %s", err)
		}

		blkData, err := section.GetByteArray("Data")
		if err != nil {
			return nil, fmt.Errorf("Could not read Section -> Data tag: %s", err)
		}
		blockLight, err := section.GetByteArray("BlockLight")
		if err != nil {
			return nil, fmt.Errorf("Could not read Section -> BlockLight tag: %s", err)
		}
		skyLight, err := section.GetByteArray("SkyLight")
		if err != nil {
			return nil, fmt.Errorf("Could not read Section -> SkyLight tag: %s", err)
		}

		for i := 0; i < chunkSectionSize; i++ {
			c.blocks[off+i] = Block{
				ID:         BlockID(uint16(blocks[i]) | (uint16(blocksAdd[i]) << 8)),
				Data:       halfbyte(blkData, i),
				BlockLight: halfbyte(blockLight, i),
				SkyLight:   halfbyte(skyLight, i)}
		}
	}

	tileEnts, err := lvl.GetList("TileEntities")
	if err != nil {
		return nil, fmt.Errorf("Could not read TileEntities tag: %s", err)
	}
	if tileEnts.Type == nbt.TAG_Compound {
		for _, _tEnt := range tileEnts.Elems {
			tEnt := _tEnt.(nbt.TagCompound)
			x, y, z, err := extractCoord(tEnt)
			if err != nil {
				return nil, fmt.Errorf("Could not Extract coords: %s", err)
			}

			_, _, x, z = BlockToChunk(x, z)

			c.blocks[calcBlockOffset(x, y, z)].TileEntity = tEnt
		}
	}

	tileTicks, err := lvl.GetList("TileTicks")
	if (err == nil) && (tileTicks.Type == nbt.TAG_Compound) {
		for _, _tTick := range tileTicks.Elems {
			tTick := _tTick.(nbt.TagCompound)
			x, y, z, err := extractCoord(tTick)
			if err != nil {
				return nil, fmt.Errorf("Could not Extract coords: %s", err)
			}

			_, _, x, z = BlockToChunk(x, z)

			x %= ChunkSizeXZ
			z %= ChunkSizeXZ

			tick := TileTick{}
			if tick.i, err = tTick.GetInt("i"); err != nil {
				return nil, fmt.Errorf("Could not read i of a TileTag tag: %s", err)
			}
			if tick.t, err = tTick.GetInt("t"); err != nil {
				return nil, fmt.Errorf("Could not read t of a TileTag tag: %s", err)
			}
			switch tick.p, err = tTick.GetInt("p"); err {
			case nil:
				tick.hasP = true
			case nbt.NotFound:
				tick.hasP = false
			default:
				return nil, fmt.Errorf("Could not read p of a TileTag tag: %s", err)
			}

			c.blocks[calcBlockOffset(x, y, z)].Tick = &tick
		}
	}

	return &c, nil
}

func (c *Chunk) toPreChunk() (*preChunk, error) {
	terraPopulated := byte(0)
	if c.populated {
		terraPopulated = 1
	}
	lvl := nbt.TagCompound{
		"xPos":             nbt.NewIntTag(c.x),
		"zPos":             nbt.NewIntTag(c.z),
		"LastUpdate":       nbt.NewLongTag(c.lastUpdate),
		"TerrainPopulated": nbt.NewByteTag(terraPopulated),
		"InhabitedTime":    nbt.NewLongTag(c.inhabitedTime),
		"HeightMap":        nbt.NewIntArrayTag(c.heightMap),
		"Entities":         nbt.Tag{nbt.TAG_Compound, c.Entities},
	}

	hasBiomes := false
	biomes := make([]byte, ChunkRectXZ)
	for i, bio := range c.biomes {
		if bio != BioUncalculated {
			hasBiomes = true
			break
		}
		biomes[i] = byte(bio)
	}
	if hasBiomes {
		lvl["Biomes"] = nbt.NewByteArrayTag(biomes)
	}

	sections := make([]nbt.TagCompound, 0)
	tileEnts := make([]nbt.TagCompound, 0)
	tileTicks := make([]nbt.TagCompound, 0)

	for subchunk := 0; subchunk < 16; subchunk++ {
		off := subchunk * chunkSectionSize

		blocks := make([]byte, chunkSectionSize)
		add := make([]byte, chunkSectionSize/2)
		data := make([]byte, chunkSectionSize/2)
		blockLight := make([]byte, chunkSectionSize/2)
		skyLight := make([]byte, chunkSectionSize/2)

		allAir, addEmpty := true, true
		for i := 0; i < chunkSectionSize; i++ {
			blk := c.blocks[i+off]
			id := blk.ID
			if id != BlkAir {
				allAir = false
			}

			blocks[i] = byte(id & 0xff)
			idH := byte(id >> 8)
			if idH != 0 {
				addEmpty = false
			}
			setHalfbyte(add, i, idH)

			setHalfbyte(data, i, blk.Data)
			setHalfbyte(blockLight, i, blk.BlockLight)
			setHalfbyte(skyLight, i, blk.SkyLight)

			x, y, z := offsetToPos(i + off)
			x, z = ChunkToBlock(int(c.x), int(c.z), x, z)

			if (blk.TileEntity != nil) && (len(blk.TileEntity) > 0) {
				// Fix coords
				blk.TileEntity["x"] = nbt.NewIntTag(int32(x))
				blk.TileEntity["y"] = nbt.NewIntTag(int32(y))
				blk.TileEntity["z"] = nbt.NewIntTag(int32(z))
				tileEnts = append(tileEnts, blk.TileEntity)
			}

			if blk.Tick != nil {
				tileTick := nbt.TagCompound{
					"x": nbt.NewIntTag(int32(x)),
					"y": nbt.NewIntTag(int32(y)),
					"z": nbt.NewIntTag(int32(z)),
					"i": nbt.NewIntTag(blk.Tick.i),
					"t": nbt.NewIntTag(blk.Tick.t),
				}
				if blk.Tick.hasP {
					tileTick["p"] = nbt.NewIntTag(blk.Tick.p)
				}
				tileTicks = append(tileTicks, tileTick)
			}
		}

		if !allAir {
			comp := nbt.TagCompound{
				"Y":          nbt.NewByteTag(byte(subchunk)),
				"Blocks":     nbt.NewByteArrayTag(blocks),
				"Data":       nbt.NewByteArrayTag(data),
				"BlockLight": nbt.NewByteArrayTag(blockLight),
				"SkyLight":   nbt.NewByteArrayTag(skyLight),
			}
			if !addEmpty {
				comp["Add"] = nbt.NewByteArrayTag(add)
			}
			sections = append(sections, comp)
		}
	}

	lvl["Sections"] = nbt.NewListTag(nbt.TAG_Compound, sections)

	if len(c.Entities) > 0 {
		lvl["Entities"] = nbt.NewListTag(nbt.TAG_Compound, c.Entities)
	} else {
		lvl["Entities"] = nbt.NewListTag(nbt.TAG_Byte, []byte{})
	}
	if len(tileEnts) > 0 {
		lvl["TileEntities"] = nbt.NewListTag(nbt.TAG_Compound, tileEnts)
	} else {
		lvl["TileEntities"] = nbt.NewListTag(nbt.TAG_Byte, []byte{})
	}
	if len(tileTicks) > 0 {
		lvl["TileTicks"] = nbt.NewListTag(nbt.TAG_Compound, tileTicks)
	}

	root := nbt.Tag{nbt.TAG_Compound, nbt.TagCompound{
		"Level": nbt.Tag{nbt.TAG_Compound, lvl},
	}}

	buf := new(bytes.Buffer)
	if err := nbt.WriteZlibdNamedTag(buf, "", root); err != nil {
		return nil, err
	}

	return &preChunk{
		ts:          c.ts,
		data:        buf.Bytes(),
		compression: compressZlib,
	}, nil
}
<commit_msg>Fixed a bug in chunk serialisation.<commit_after>package mcmap

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/kch42/gonbt/nbt"
	"time"
)

const (
	_ = iota
	compressGZip
	compressZlib
)

type preChunk struct {
	ts          time.Time
	data        []byte
	compression byte
}

var (
	UnknownCompression = errors.New("Unknown chunk compression")
)

func halfbyte(b []byte, i int) byte {
	if i%2 == 0 {
		return b[i/2] & 0x0f
	}
	return (b[i/2] >> 4) & 0x0f
}

func setHalfbyte(b []byte, i int, v byte) {
	v &= 0xf
	if i%2 == 0 {
		b[i/2] |= v
	} else {
		b[i/2] |= v << 4
	}
}

func extractCoord(tc nbt.TagCompound) (x, y, z int, err error) {
	var _x, _y, _z int32
	if _x, err = tc.GetInt("x"); err != nil {
		return
	}
	if _y, err = tc.GetInt("y"); err != nil {
		return
	}
	_z, err = tc.GetInt("z")
	x, y, z = int(_x), int(_y), int(_z)
	return
}

func (pc *preChunk) getLevelTag() (nbt.TagCompound, error) {
	r := bytes.NewReader(pc.data)

	var root nbt.Tag
	var err error
	switch pc.compression {
	case compressGZip:
		root, _, err = nbt.ReadGzipdNamedTag(r)
	case compressZlib:
		root, _, err = nbt.ReadZlibdNamedTag(r)
	default:
		err = UnknownCompression
	}

	if err != nil {
		return nil, err
	}

	if root.Type != nbt.TAG_Compound {
		return nil, errors.New("Root tag is not a TAG_Compound")
	}

	lvl, err := root.Payload.(nbt.TagCompound).GetCompound("Level")
	if err != nil {
		return nil, fmt.Errorf("Could not read Level tag: %s", err)
	}

	return lvl, nil
}

func (pc *preChunk) toChunk(reg *Region) (*Chunk, error) {
	c := Chunk{ts: pc.ts, reg: reg}

	lvl, err := pc.getLevelTag()
	if err != nil {
		return nil, err
	}

	c.x, err = lvl.GetInt("xPos")
	if err != nil {
		return nil, fmt.Errorf("Could not read xPos tag: %s", err)
	}
	c.z, err = lvl.GetInt("zPos")
	if err != nil {
		return nil, fmt.Errorf("Could not read zPos tag: %s", err)
	}

	c.lastUpdate, err = lvl.GetLong("LastUpdate")
	if err != nil {
		return nil, fmt.Errorf("Could not read LastUpdate tag: %s", err)
	}

	populated, err := lvl.GetByte("TerrainPopulated")
	switch err {
	case nil:
	case nbt.NotFound:
		populated = 1
	default:
		return nil, fmt.Errorf("Could not read TerrainPopulated tag: %s", err)
	}
	c.populated = (populated == 1)

	c.inhabitedTime, err = lvl.GetLong("InhabitedTime")
	switch err {
	case nil:
	case nbt.NotFound:
		c.inhabitedTime = 0
	default:
		return nil, fmt.Errorf("Could not read InhabitatedTime tag: %s", err)
	}

	c.biomes = make([]Biome, ChunkRectXZ)
	biomes, err := lvl.GetByteArray("Biomes")
	switch err {
	case nil:
		for i, bio := range biomes {
			c.biomes[i] = Biome(bio)
		}
	case nbt.NotFound:
		for i := 0; i < ChunkRectXZ; i++ {
			c.biomes[i] = BioUncalculated
		}
	default:
		return nil, fmt.Errorf("Could not read Biomes tag: %s", err)
	}

	c.heightMap, err = lvl.GetIntArray("HeightMap")
	if err != nil {
		return nil, fmt.Errorf("Could not read HeightMap tag: %s", err)
	}

	ents, err := lvl.GetList("Entities")
	if err != nil {
		return nil, fmt.Errorf("Could not read Entities tag: %s", err)
	}
	if ents.Type != nbt.TAG_Compound {
		c.Entities = []nbt.TagCompound{}
	} else {
		c.Entities = make([]nbt.TagCompound, len(ents.Elems))
		for i, ent := range ents.Elems {
			c.Entities[i] = ent.(nbt.TagCompound)
		}
	}

	sections, err := lvl.GetList("Sections")
	if (err != nil) || (sections.Type != nbt.TAG_Compound) {
		return nil, fmt.Errorf("Could not read Section tag: %s", err)
	}

	c.blocks = make([]Block, ChunkSize)
	for _, _section := range sections.Elems {
		section := _section.(nbt.TagCompound)

		y, err := section.GetByte("Y")
		if err != nil {
			return nil, fmt.Errorf("Could not read Section -> Y tag: %s", err)
		}
		off := int(y) * chunkSectionSize

		blocks, err := section.GetByteArray("Blocks")
		if err != nil {
			return nil, fmt.Errorf("Could not read Section -> Blocks tag: %s", err)
		}
		blocksAdd := make([]byte, chunkSectionSize)
		add, err := section.GetByteArray("Add")
		switch err {
		case nil:
			for i := 0; i < chunkSectionSize; i++ {
				blocksAdd[i] = halfbyte(add, i)
			}
		case nbt.NotFound:
		default:
			return nil, fmt.Errorf("Could not read Section -> Add tag: %s", err)
		}

		blkData, err := section.GetByteArray("Data")
		if err != nil {
			return nil, fmt.Errorf("Could not read Section -> Data tag: %s", err)
		}
		blockLight, err := section.GetByteArray("BlockLight")
		if err != nil {
			return nil, fmt.Errorf("Could not read Section -> BlockLight tag: %s", err)
		}
		skyLight, err := section.GetByteArray("SkyLight")
		if err != nil {
			return nil, fmt.Errorf("Could not read Section -> SkyLight tag: %s", err)
		}

		for i := 0; i < chunkSectionSize; i++ {
			c.blocks[off+i] = Block{
				ID:         BlockID(uint16(blocks[i]) | (uint16(blocksAdd[i]) << 8)),
				Data:       halfbyte(blkData, i),
				BlockLight: halfbyte(blockLight, i),
				SkyLight:   halfbyte(skyLight, i)}
		}
	}

	tileEnts, err := lvl.GetList("TileEntities")
	if err != nil {
		return nil, fmt.Errorf("Could not read TileEntities tag: %s", err)
	}
	if tileEnts.Type == nbt.TAG_Compound {
		for _, _tEnt := range tileEnts.Elems {
			tEnt := _tEnt.(nbt.TagCompound)
			x, y, z, err := extractCoord(tEnt)
			if err != nil {
				return nil, fmt.Errorf("Could not Extract coords: %s", err)
			}

			_, _, x, z = BlockToChunk(x, z)

			c.blocks[calcBlockOffset(x, y, z)].TileEntity = tEnt
		}
	}

	tileTicks, err := lvl.GetList("TileTicks")
	if (err == nil) && (tileTicks.Type == nbt.TAG_Compound) {
		for _, _tTick := range tileTicks.Elems {
			tTick := _tTick.(nbt.TagCompound)
			x, y, z, err := extractCoord(tTick)
			if err != nil {
				return nil, fmt.Errorf("Could not Extract coords: %s", err)
			}

			_, _, x, z = BlockToChunk(x, z)

			x %= ChunkSizeXZ
			z %= ChunkSizeXZ

			tick := TileTick{}
			if tick.i, err = tTick.GetInt("i"); err != nil {
				return nil, fmt.Errorf("Could not read i of a TileTag tag: %s", err)
			}
			if tick.t, err = tTick.GetInt("t"); err != nil {
				return nil, fmt.Errorf("Could not read t of a TileTag tag: %s", err)
			}
			switch tick.p, err = tTick.GetInt("p"); err {
			case nil:
				tick.hasP = true
			case nbt.NotFound:
				tick.hasP = false
			default:
				return nil, fmt.Errorf("Could not read p of a TileTag tag: %s", err)
			}

			c.blocks[calcBlockOffset(x, y, z)].Tick = &tick
		}
	}

	return &c, nil
}

func (c *Chunk) toPreChunk() (*preChunk, error) {
	terraPopulated := byte(0)
	if c.populated {
		terraPopulated = 1
	}
	lvl := nbt.TagCompound{
		"xPos":             nbt.NewIntTag(c.x),
		"zPos":             nbt.NewIntTag(c.z),
		"LastUpdate":       nbt.NewLongTag(c.lastUpdate),
		"TerrainPopulated": nbt.NewByteTag(terraPopulated),
		"InhabitedTime":    nbt.NewLongTag(c.inhabitedTime),
		"HeightMap":        nbt.NewIntArrayTag(c.heightMap),
		"Entities":         nbt.Tag{nbt.TAG_Compound, c.Entities},
	}

	hasBiomes := false
	biomes := make([]byte, ChunkRectXZ)
	for i, bio := range c.biomes {
		if bio != BioUncalculated {
			hasBiomes = true
		}
		biomes[i] = byte(bio)
	}
	if hasBiomes {
		lvl["Biomes"] = nbt.NewByteArrayTag(biomes)
	}

	sections := make([]nbt.TagCompound, 0)
	tileEnts := make([]nbt.TagCompound, 0)
	tileTicks := make([]nbt.TagCompound, 0)

	for subchunk := 0; subchunk < 16; subchunk++ {
		off := subchunk * chunkSectionSize

		blocks := make([]byte, chunkSectionSize)
		add := make([]byte, chunkSectionSize/2)
		data := make([]byte, chunkSectionSize/2)
		blockLight := make([]byte, chunkSectionSize/2)
		skyLight := make([]byte, chunkSectionSize/2)

		allAir, addEmpty := true, true
		for i := 0; i < chunkSectionSize; i++ {
			blk := c.blocks[i+off]
			id := blk.ID
			if id != BlkAir {
				allAir = false
			}

			blocks[i] = byte(id & 0xff)
			idH := byte(id >> 8)
			if idH != 0 {
				addEmpty = false
			}
			setHalfbyte(add, i, idH)

			setHalfbyte(data, i, blk.Data)
			setHalfbyte(blockLight, i, blk.BlockLight)
			setHalfbyte(skyLight, i, blk.SkyLight)

			x, y, z := offsetToPos(i + off)
			x, z = ChunkToBlock(int(c.x), int(c.z), x, z)

			if (blk.TileEntity != nil) && (len(blk.TileEntity) > 0) {
				// Fix coords
				blk.TileEntity["x"] = nbt.NewIntTag(int32(x))
				blk.TileEntity["y"] = nbt.NewIntTag(int32(y))
				blk.TileEntity["z"] = nbt.NewIntTag(int32(z))
				tileEnts = append(tileEnts, blk.TileEntity)
			}

			if blk.Tick != nil {
				tileTick := nbt.TagCompound{
					"x": nbt.NewIntTag(int32(x)),
					"y": nbt.NewIntTag(int32(y)),
					"z": nbt.NewIntTag(int32(z)),
					"i": nbt.NewIntTag(blk.Tick.i),
					"t": nbt.NewIntTag(blk.Tick.t),
				}
				if blk.Tick.hasP {
					tileTick["p"] = nbt.NewIntTag(blk.Tick.p)
				}
				tileTicks = append(tileTicks, tileTick)
			}
		}

		if !allAir {
			comp := nbt.TagCompound{
				"Y":          nbt.NewByteTag(byte(subchunk)),
				"Blocks":     nbt.NewByteArrayTag(blocks),
				"Data":       nbt.NewByteArrayTag(data),
				"BlockLight": nbt.NewByteArrayTag(blockLight),
				"SkyLight":   nbt.NewByteArrayTag(skyLight),
			}
			if !addEmpty {
				comp["Add"] = nbt.NewByteArrayTag(add)
			}
			sections = append(sections, comp)
		}
	}

	lvl["Sections"] = nbt.NewListTag(nbt.TAG_Compound, sections)

	if len(c.Entities) > 0 {
		lvl["Entities"] = nbt.NewListTag(nbt.TAG_Compound, c.Entities)
	} else {
		lvl["Entities"] = nbt.NewListTag(nbt.TAG_Byte, []byte{})
	}
	if len(tileEnts) > 0 {
		lvl["TileEntities"] = nbt.NewListTag(nbt.TAG_Compound, tileEnts)
	} else {
		lvl["TileEntities"] = nbt.NewListTag(nbt.TAG_Byte, []byte{})
	}
	if len(tileTicks) > 0 {
		lvl["TileTicks"] = nbt.NewListTag(nbt.TAG_Compound, tileTicks)
	}

	root := nbt.Tag{nbt.TAG_Compound, nbt.TagCompound{
		"Level": nbt.Tag{nbt.TAG_Compound, lvl},
	}}

	buf := new(bytes.Buffer)
	if err := nbt.WriteZlibdNamedTag(buf, "", root); err != nil {
		return nil, err
	}

	return &preChunk{
		ts:          c.ts,
		data:        buf.Bytes(),
		compression: compressZlib,
	}, nil
}
<|endoftext|>