<commit_before>// Copyright 2011 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 main

import (
	"bufio"
	"encoding/json"
	"io"
	"os"
	"strings"
	"text/template"
)

var cmdList = &Command{
	UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
	Short:     "list packages",
	Long: `
List lists the packages named by the import paths, one per line.

The default output shows the package import path:

    code.google.com/p/google-api-go-client/books/v1
    code.google.com/p/goauth2/oauth
    code.google.com/p/sqlite

The -f flag specifies an alternate format for the list, using the
syntax of package template.  The default output is equivalent to -f
'{{.ImportPath}}'. The struct being passed to the template is:

    type Package struct {
        Dir        string // directory containing package sources
        ImportPath string // import path of package in dir
        Name       string // package name
        Doc        string // package documentation string
        Target     string // install path
        Goroot     bool   // is this package in the Go root?
        Standard   bool   // is this package part of the standard Go library?
        Stale      bool   // would 'go install' do anything for this package?
        Root       string // Go root or Go path dir containing this package

        // Source files
        GoFiles  []string       // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
        CgoFiles []string       // .go sources files that import "C"
        IgnoredGoFiles []string // .go sources ignored due to build constraints
        CFiles   []string       // .c source files
        CXXFiles []string       // .cc, .cxx and .cpp source files
        MFiles   []string       // .m source files
        HFiles   []string       // .h, .hh, .hpp and .hxx source files
        SFiles   []string       // .s source files
        SwigFiles []string      // .swig files
        SwigCXXFiles []string   // .swigcxx files
        SysoFiles []string      // .syso object files to add to archive

        // Cgo directives
        CgoCFLAGS    []string // cgo: flags for C compiler
        CgoCPPFLAGS  []string // cgo: flags for C preprocessor
        CgoCXXFLAGS  []string // cgo: flags for C++ compiler
        CgoLDFLAGS   []string // cgo: flags for linker
        CgoPkgConfig []string // cgo: pkg-config names

        // Dependency information
        Imports []string // import paths used by this package
        Deps    []string // all (recursively) imported dependencies

        // Error information
        Incomplete bool            // this package or a dependency has an error
        Error      *PackageError   // error loading package
        DepsErrors []*PackageError // errors loading dependencies

        TestGoFiles  []string // _test.go files in package
        TestImports  []string // imports from TestGoFiles
        XTestGoFiles []string // _test.go files outside package
        XTestImports []string // imports from XTestGoFiles
    }

The template function "join" calls strings.Join.

The template function "context" returns the build context, defined as:

	type Context struct {
		GOARCH        string   // target architecture
		GOOS          string   // target operating system
		GOROOT        string   // Go root
		GOPATH        string   // Go path
		CgoEnabled    bool     // whether cgo can be used
		UseAllFiles   bool     // use files regardless of +build lines, file names
		Compiler      string   // compiler to assume when computing target paths
		BuildTags     []string // build constraints to match in +build lines
		ReleaseTags   []string // releases the current release is compatible with
		InstallSuffix string   // suffix to use in the name of the install dir
	}

For more information about the meaning of these fields see the documentation
for the go/build package's Context type.

The -json flag causes the package data to be printed in JSON format
instead of using the template format.

The -e flag changes the handling of erroneous packages, those that
cannot be found or are malformed.  By default, the list command
prints an error to standard error for each erroneous package and
omits the packages from consideration during the usual printing.
With the -e flag, the list command never prints errors to standard
error and instead processes the erroneous packages with the usual
printing.  Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing
(zeroed).

For more about build flags, see 'go help build'.

For more about specifying packages, see 'go help packages'.
	`,
}

func init() {
	cmdList.Run = runList // break init cycle
	addBuildFlags(cmdList)
}

var listE = cmdList.Flag.Bool("e", false, "")
var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
var listJson = cmdList.Flag.Bool("json", false, "")
var nl = []byte{'\n'}

func runList(cmd *Command, args []string) {
	out := newTrackingWriter(os.Stdout)
	defer out.w.Flush()

	var do func(*Package)
	if *listJson {
		do = func(p *Package) {
			b, err := json.MarshalIndent(p, "", "\t")
			if err != nil {
				out.Flush()
				fatalf("%s", err)
			}
			out.Write(b)
			out.Write(nl)
		}
	} else {
		var cachedCtxt *Context
		context := func() *Context {
			if cachedCtxt == nil {
				cachedCtxt = newContext(&buildContext)
			}
			return cachedCtxt
		}
		fm := template.FuncMap{
			"join":    strings.Join,
			"context": context,
		}
		tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
		if err != nil {
			fatalf("%s", err)
		}
		do = func(p *Package) {
			if err := tmpl.Execute(out, p); err != nil {
				out.Flush()
				fatalf("%s", err)
			}
			if out.NeedNL() {
				out.Write([]byte{'\n'})
			}
		}
	}

	load := packages
	if *listE {
		load = packagesAndErrors
	}

	for _, pkg := range load(args) {
		do(pkg)
	}
}

// TrackingWriter tracks the last byte written on every write so
// we can avoid printing a newline if one was already written or
// if there is no output at all.
type TrackingWriter struct {
	w    *bufio.Writer
	last byte
}

func newTrackingWriter(w io.Writer) *TrackingWriter {
	return &TrackingWriter{
		w:    bufio.NewWriter(w),
		last: '\n',
	}
}

func (t *TrackingWriter) Write(p []byte) (n int, err error) {
	n, err = t.w.Write(p)
	if n > 0 {
		t.last = p[n-1]
	}
	return
}

func (t *TrackingWriter) Flush() {
	t.w.Flush()
}

func (t *TrackingWriter) NeedNL() bool {
	return t.last != '\n'
}
<commit_msg>cmd/go: simplify code, reduce allocations.<commit_after>// Copyright 2011 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 main

import (
	"bufio"
	"encoding/json"
	"io"
	"os"
	"strings"
	"text/template"
)

var cmdList = &Command{
	UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
	Short:     "list packages",
	Long: `
List lists the packages named by the import paths, one per line.

The default output shows the package import path:

    code.google.com/p/google-api-go-client/books/v1
    code.google.com/p/goauth2/oauth
    code.google.com/p/sqlite

The -f flag specifies an alternate format for the list, using the
syntax of package template.  The default output is equivalent to -f
'{{.ImportPath}}'. The struct being passed to the template is:

    type Package struct {
        Dir        string // directory containing package sources
        ImportPath string // import path of package in dir
        Name       string // package name
        Doc        string // package documentation string
        Target     string // install path
        Goroot     bool   // is this package in the Go root?
        Standard   bool   // is this package part of the standard Go library?
        Stale      bool   // would 'go install' do anything for this package?
        Root       string // Go root or Go path dir containing this package

        // Source files
        GoFiles  []string       // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
        CgoFiles []string       // .go sources files that import "C"
        IgnoredGoFiles []string // .go sources ignored due to build constraints
        CFiles   []string       // .c source files
        CXXFiles []string       // .cc, .cxx and .cpp source files
        MFiles   []string       // .m source files
        HFiles   []string       // .h, .hh, .hpp and .hxx source files
        SFiles   []string       // .s source files
        SwigFiles []string      // .swig files
        SwigCXXFiles []string   // .swigcxx files
        SysoFiles []string      // .syso object files to add to archive

        // Cgo directives
        CgoCFLAGS    []string // cgo: flags for C compiler
        CgoCPPFLAGS  []string // cgo: flags for C preprocessor
        CgoCXXFLAGS  []string // cgo: flags for C++ compiler
        CgoLDFLAGS   []string // cgo: flags for linker
        CgoPkgConfig []string // cgo: pkg-config names

        // Dependency information
        Imports []string // import paths used by this package
        Deps    []string // all (recursively) imported dependencies

        // Error information
        Incomplete bool            // this package or a dependency has an error
        Error      *PackageError   // error loading package
        DepsErrors []*PackageError // errors loading dependencies

        TestGoFiles  []string // _test.go files in package
        TestImports  []string // imports from TestGoFiles
        XTestGoFiles []string // _test.go files outside package
        XTestImports []string // imports from XTestGoFiles
    }

The template function "join" calls strings.Join.

The template function "context" returns the build context, defined as:

	type Context struct {
		GOARCH        string   // target architecture
		GOOS          string   // target operating system
		GOROOT        string   // Go root
		GOPATH        string   // Go path
		CgoEnabled    bool     // whether cgo can be used
		UseAllFiles   bool     // use files regardless of +build lines, file names
		Compiler      string   // compiler to assume when computing target paths
		BuildTags     []string // build constraints to match in +build lines
		ReleaseTags   []string // releases the current release is compatible with
		InstallSuffix string   // suffix to use in the name of the install dir
	}

For more information about the meaning of these fields see the documentation
for the go/build package's Context type.

The -json flag causes the package data to be printed in JSON format
instead of using the template format.

The -e flag changes the handling of erroneous packages, those that
cannot be found or are malformed.  By default, the list command
prints an error to standard error for each erroneous package and
omits the packages from consideration during the usual printing.
With the -e flag, the list command never prints errors to standard
error and instead processes the erroneous packages with the usual
printing.  Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing
(zeroed).

For more about build flags, see 'go help build'.

For more about specifying packages, see 'go help packages'.
	`,
}

func init() {
	cmdList.Run = runList // break init cycle
	addBuildFlags(cmdList)
}

var listE = cmdList.Flag.Bool("e", false, "")
var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
var listJson = cmdList.Flag.Bool("json", false, "")
var nl = []byte{'\n'}

func runList(cmd *Command, args []string) {
	out := newTrackingWriter(os.Stdout)
	defer out.w.Flush()

	var do func(*Package)
	if *listJson {
		do = func(p *Package) {
			b, err := json.MarshalIndent(p, "", "\t")
			if err != nil {
				out.Flush()
				fatalf("%s", err)
			}
			out.Write(b)
			out.Write(nl)
		}
	} else {
		var cachedCtxt *Context
		context := func() *Context {
			if cachedCtxt == nil {
				cachedCtxt = newContext(&buildContext)
			}
			return cachedCtxt
		}
		fm := template.FuncMap{
			"join":    strings.Join,
			"context": context,
		}
		tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
		if err != nil {
			fatalf("%s", err)
		}
		do = func(p *Package) {
			if err := tmpl.Execute(out, p); err != nil {
				out.Flush()
				fatalf("%s", err)
			}
			if out.NeedNL() {
				out.Write(nl)
			}
		}
	}

	load := packages
	if *listE {
		load = packagesAndErrors
	}

	for _, pkg := range load(args) {
		do(pkg)
	}
}

// TrackingWriter tracks the last byte written on every write so
// we can avoid printing a newline if one was already written or
// if there is no output at all.
type TrackingWriter struct {
	w    *bufio.Writer
	last byte
}

func newTrackingWriter(w io.Writer) *TrackingWriter {
	return &TrackingWriter{
		w:    bufio.NewWriter(w),
		last: '\n',
	}
}

func (t *TrackingWriter) Write(p []byte) (n int, err error) {
	n, err = t.w.Write(p)
	if n > 0 {
		t.last = p[n-1]
	}
	return
}

func (t *TrackingWriter) Flush() {
	t.w.Flush()
}

func (t *TrackingWriter) NeedNL() bool {
	return t.last != '\n'
}
<|endoftext|>


<commit_before>package common

import (
	"common/crypto"
)

// A Segment is an erasure-coded piece of a Ring, containing both the data and its corresponding index.
type Segment struct {
	Data  []byte
	Index uint8
}

// A Sector is a block of data, along with its erasure-coding parameters.
// k is the number of non-redundant segments, and b is the number of bytes per segment.
type Sector struct {
	Data   []byte
	Hash   crypto.Hash
	length int
	k, b   int
}

// A Ring is an array of QuorumSize Segments, ready for distribution across a Quorum.
type Ring [QuorumSize]Segment

// NewSector creates a Sector from data.
func NewSector(data []byte) (s *Sector, err error) {
	// calculate hash
	hash, err := crypto.CalculateHash(data)

	s = &Sector{
		data,
		hash,
		len(data),
		0, 0,
	}
	return
}

// SetRedundancy sets the erasure-coding parameters of a Sector based on a provided k value.
func (s *Sector) SetRedundancy(k int) {
	s.k = k
	s.b = len(s.Data) / s.k
	if s.b%64 != 0 {
		s.b += 64 - (s.b % 64)
	}
}

func (s *Sector) GetRedundancy() int {
	return s.k
}

func (s *Sector) GetBytesPerSegment() int {
	return s.b
}

func (s *Sector) GetLength() int {
	return s.length
}
<commit_msg>move encoding params to Ring<commit_after>package common

import (
	"common/crypto"
)

// A Sector is a logical block of data.
type Sector struct {
	Data []byte
	Hash crypto.Hash
}

// A Ring is an erasure-coded Sector, along with the parameters used to encode it.
// k is the number of non-redundant segments, and b is the number of bytes per segment.
type Ring struct {
	Segs      []Segment
	SegHashes []crypto.Hash
	k, b      int
	length    int
}

// A Segment is an erasure-coded piece of a Ring, containing both the data and its corresponding index.
type Segment struct {
	Data  []byte
	Index uint8
}

// NewSector creates a Sector from data.
func NewSector(data []byte) (s *Sector, err error) {
	// calculate hash
	hash, err := crypto.CalculateHash(data)

	s = &Sector{
		Data: data,
		Hash: hash,
	}
	return
}

// NewRing creates an empty Ring using the specified encoding parameters.
func NewRing(k, b, length int) *Ring {
	return &Ring{
		k:      k,
		b:      b,
		length: length,
	}
}

// AddSegment adds a Segment to a Ring
func (r *Ring) AddSegment(seg *Segment) (err error) {
	sh, err := crypto.CalculateHash(seg.Data)
	if err != nil {
		return
	}
	r.Segs = append(r.Segs, *seg)
	r.SegHashes = append(r.SegHashes, sh)
	return
}

func (r *Ring) GetRedundancy() int {
	return r.k
}

func (r *Ring) GetBytesPerSegment() int {
	return r.b
}

func (r *Ring) GetLength() int {
	return r.length
}
<|endoftext|>


<commit_before>// Copyright 2011 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 runtime_test

import "testing"

const N = 20

func BenchmarkAppend(b *testing.B) {
	b.StopTimer()
	x := make([]int, 0, N)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x = x[0:0]
		for j := 0; j < N; j++ {
			x = append(x, j)
		}
	}
}

func benchmarkAppendBytes(b *testing.B, length int) {
	b.StopTimer()
	x := make([]byte, 0, N)
	y := make([]byte, length)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x = x[0:0]
		for j := 0; j < N; j++ {
			x = append(x, y...)
		}
	}
}

func BenchmarkAppend1Byte(b *testing.B) {
	benchmarkAppendBytes(b, 1)
}

func BenchmarkAppend4Bytes(b *testing.B) {
	benchmarkAppendBytes(b, 4)
}

func BenchmarkAppend8Bytes(b *testing.B) {
	benchmarkAppendBytes(b, 8)
}

func BenchmarkAppend16Bytes(b *testing.B) {
	benchmarkAppendBytes(b, 16)
}

func BenchmarkAppend32Bytes(b *testing.B) {
	benchmarkAppendBytes(b, 32)
}

func benchmarkAppendStr(b *testing.B, str string) {
	b.StopTimer()
	x := make([]byte, 0, N)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x = x[0:0]
		for j := 0; j < N; j++ {
			x = append(x, str...)
		}
	}
}

func BenchmarkAppendStr1Byte(b *testing.B) {
	benchmarkAppendStr(b, "1")
}

func BenchmarkAppendStr4Bytes(b *testing.B) {
	benchmarkAppendStr(b, "1234")
}

func BenchmarkAppendStr8Bytes(b *testing.B) {
	benchmarkAppendStr(b, "12345678")
}

func BenchmarkAppendStr16Bytes(b *testing.B) {
	benchmarkAppendStr(b, "1234567890123456")
}

func BenchmarkAppendStr32Bytes(b *testing.B) {
	benchmarkAppendStr(b, "12345678901234567890123456789012")
}

func BenchmarkAppendSpecialCase(b *testing.B) {
	b.StopTimer()
	x := make([]int, 0, N)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x = x[0:0]
		for j := 0; j < N; j++ {
			if len(x) < cap(x) {
				x = x[:len(x)+1]
				x[len(x)-1] = j
			} else {
				x = append(x, j)
			}
		}
	}
}

var x []int

func f() int {
	x[:1][0] = 3
	return 2
}

func TestSideEffectOrder(t *testing.T) {
	x = make([]int, 0, 10)
	x = append(x, 1, f())
	if x[0] != 1 || x[1] != 2 {
		t.Error("append failed: ", x[0], x[1])
	}
}

func TestAppendOverlap(t *testing.T) {
	x := []byte("1234")
	x = append(x[1:], x...) // p > q in runtime·appendslice.
	got := string(x)
	want := "2341234"
	if got != want {
		t.Errorf("overlap failed: got %q want %q", got, want)
	}
}
<commit_msg>runtime: benchmark for appending N bytes should not append N² bytes.<commit_after>// Copyright 2011 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 runtime_test

import "testing"

const N = 20

func BenchmarkAppend(b *testing.B) {
	b.StopTimer()
	x := make([]int, 0, N)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x = x[0:0]
		for j := 0; j < N; j++ {
			x = append(x, j)
		}
	}
}

func benchmarkAppendBytes(b *testing.B, length int) {
	b.StopTimer()
	x := make([]byte, 0, N)
	y := make([]byte, length)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x = x[0:0]
		x = append(x, y...)
	}
}

func BenchmarkAppend1Byte(b *testing.B) {
	benchmarkAppendBytes(b, 1)
}

func BenchmarkAppend4Bytes(b *testing.B) {
	benchmarkAppendBytes(b, 4)
}

func BenchmarkAppend8Bytes(b *testing.B) {
	benchmarkAppendBytes(b, 8)
}

func BenchmarkAppend16Bytes(b *testing.B) {
	benchmarkAppendBytes(b, 16)
}

func BenchmarkAppend32Bytes(b *testing.B) {
	benchmarkAppendBytes(b, 32)
}

func benchmarkAppendStr(b *testing.B, str string) {
	b.StopTimer()
	x := make([]byte, 0, N)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x = x[0:0]
		x = append(x, str...)
	}
}

func BenchmarkAppendStr1Byte(b *testing.B) {
	benchmarkAppendStr(b, "1")
}

func BenchmarkAppendStr4Bytes(b *testing.B) {
	benchmarkAppendStr(b, "1234")
}

func BenchmarkAppendStr8Bytes(b *testing.B) {
	benchmarkAppendStr(b, "12345678")
}

func BenchmarkAppendStr16Bytes(b *testing.B) {
	benchmarkAppendStr(b, "1234567890123456")
}

func BenchmarkAppendStr32Bytes(b *testing.B) {
	benchmarkAppendStr(b, "12345678901234567890123456789012")
}

func BenchmarkAppendSpecialCase(b *testing.B) {
	b.StopTimer()
	x := make([]int, 0, N)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x = x[0:0]
		for j := 0; j < N; j++ {
			if len(x) < cap(x) {
				x = x[:len(x)+1]
				x[len(x)-1] = j
			} else {
				x = append(x, j)
			}
		}
	}
}

var x []int

func f() int {
	x[:1][0] = 3
	return 2
}

func TestSideEffectOrder(t *testing.T) {
	x = make([]int, 0, 10)
	x = append(x, 1, f())
	if x[0] != 1 || x[1] != 2 {
		t.Error("append failed: ", x[0], x[1])
	}
}

func TestAppendOverlap(t *testing.T) {
	x := []byte("1234")
	x = append(x[1:], x...) // p > q in runtime·appendslice.
	got := string(x)
	want := "2341234"
	if got != want {
		t.Errorf("overlap failed: got %q want %q", got, want)
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 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 syscall

import (
	"sync"
	"sync/atomic"
	"unsafe"
)

// DLLError describes reasons for DLL load failures.
type DLLError struct {
	Err     error
	ObjName string
	Msg     string
}

func (e *DLLError) Error() string { return e.Msg }

// Implemented in ../runtime/syscall_windows.goc.
func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)
func loadlibrary(filename *uint16) (handle uintptr, err Errno)
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)

// A DLL implements access to a single DLL.
type DLL struct {
	Name   string
	Handle Handle
}

// LoadDLL loads DLL file into memory.
func LoadDLL(name string) (dll *DLL, err error) {
	namep, err := UTF16PtrFromString(name)
	if err != nil {
		return nil, err
	}
	h, e := loadlibrary(namep)
	if e != 0 {
		return nil, &DLLError{
			Err:     e,
			ObjName: name,
			Msg:     "Failed to load " + name + ": " + e.Error(),
		}
	}
	d := &DLL{
		Name:   name,
		Handle: Handle(h),
	}
	return d, nil
}

// MustLoadDLL is like LoadDLL but panics if load operation failes.
func MustLoadDLL(name string) *DLL {
	d, e := LoadDLL(name)
	if e != nil {
		panic(e)
	}
	return d
}

// FindProc searches DLL d for procedure named name and returns *Proc
// if found. It returns an error if search fails.
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
	namep, err := BytePtrFromString(name)
	if err != nil {
		return nil, err
	}
	a, e := getprocaddress(uintptr(d.Handle), namep)
	if e != 0 {
		return nil, &DLLError{
			Err:     e,
			ObjName: name,
			Msg:     "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
		}
	}
	p := &Proc{
		Dll:  d,
		Name: name,
		addr: a,
	}
	return p, nil
}

// MustFindProc is like FindProc but panics if search fails.
func (d *DLL) MustFindProc(name string) *Proc {
	p, e := d.FindProc(name)
	if e != nil {
		panic(e)
	}
	return p
}

// Release unloads DLL d from memory.
func (d *DLL) Release() (err error) {
	return FreeLibrary(d.Handle)
}

// A Proc implements access to a procedure inside a DLL.
type Proc struct {
	Dll  *DLL
	Name string
	addr uintptr
}

// Addr returns the address of the procedure represented by p.
// The return value can be passed to Syscall to run the procedure.
func (p *Proc) Addr() uintptr {
	return p.addr
}

// Call executes procedure p with arguments a.
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, err error) {
	switch len(a) {
	case 0:
		return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
	case 1:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
	case 2:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
	case 3:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
	case 4:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
	case 5:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
	case 6:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
	case 7:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
	case 8:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
	case 9:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
	case 10:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
	case 11:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
	case 12:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
	case 13:
		return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
	case 14:
		return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
	case 15:
		return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
	default:
		panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
	}
	return
}

// A LazyDLL implements access to a single DLL.
// It will delay the load of the DLL until the first
// call to its Handle method or to one of its
// LazyProc's Addr method.
type LazyDLL struct {
	mu   sync.Mutex
	dll  *DLL // non nil once DLL is loaded
	Name string
}

// Load loads DLL file d.Name into memory. It returns an error if fails.
// Load will not try to load DLL, if it is already loaded into memory.
func (d *LazyDLL) Load() error {
	// Non-racy version of:
	// if d.dll == nil {
	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
		d.mu.Lock()
		defer d.mu.Unlock()
		if d.dll == nil {
			dll, e := LoadDLL(d.Name)
			if e != nil {
				return e
			}
			// Non-racy version of:
			// d.dll = dll
			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
		}
	}
	return nil
}

// mustLoad is like Load but panics if search fails.
func (d *LazyDLL) mustLoad() {
	e := d.Load()
	if e != nil {
		panic(e)
	}
}

// Handle returns d's module handle.
func (d *LazyDLL) Handle() uintptr {
	d.mustLoad()
	return uintptr(d.dll.Handle)
}

// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
func (d *LazyDLL) NewProc(name string) *LazyProc {
	return &LazyProc{l: d, Name: name}
}

// NewLazyDLL creates new LazyDLL associated with DLL file.
func NewLazyDLL(name string) *LazyDLL {
	return &LazyDLL{Name: name}
}

// A LazyProc implements access to a procedure inside a LazyDLL.
// It delays the lookup until the Addr method is called.
type LazyProc struct {
	mu   sync.Mutex
	Name string
	l    *LazyDLL
	proc *Proc
}

// Find searches DLL for procedure named p.Name. It returns
// an error if search fails. Find will not search procedure,
// if it is already found and loaded into memory.
func (p *LazyProc) Find() error {
	// Non-racy version of:
	// if p.proc == nil {
	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
		p.mu.Lock()
		defer p.mu.Unlock()
		if p.proc == nil {
			e := p.l.Load()
			if e != nil {
				return e
			}
			proc, e := p.l.dll.FindProc(p.Name)
			if e != nil {
				return e
			}
			// Non-racy version of:
			// p.proc = proc
			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
		}
	}
	return nil
}

// mustFind is like Find but panics if search fails.
func (p *LazyProc) mustFind() {
	e := p.Find()
	if e != nil {
		panic(e)
	}
}

// Addr returns the address of the procedure represented by p.
// The return value can be passed to Syscall to run the procedure.
func (p *LazyProc) Addr() uintptr {
	p.mustFind()
	return p.proc.Addr()
}

// Call executes procedure p with arguments a.
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, err error) {
	p.mustFind()
	return p.proc.Call(a...)
}
<commit_msg>syscall: (*Proc).Call should return nil error when no error occurs Fixes issue 4686.<commit_after>// Copyright 2011 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 syscall

import (
	"sync"
	"sync/atomic"
	"unsafe"
)

// DLLError describes reasons for DLL load failures.
type DLLError struct {
	Err     error
	ObjName string
	Msg     string
}

func (e *DLLError) Error() string { return e.Msg }

// Implemented in ../runtime/syscall_windows.goc.
func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)
func loadlibrary(filename *uint16) (handle uintptr, err Errno)
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)

// A DLL implements access to a single DLL.
type DLL struct {
	Name   string
	Handle Handle
}

// LoadDLL loads DLL file into memory.
func LoadDLL(name string) (dll *DLL, err error) {
	namep, err := UTF16PtrFromString(name)
	if err != nil {
		return nil, err
	}
	h, e := loadlibrary(namep)
	if e != 0 {
		return nil, &DLLError{
			Err:     e,
			ObjName: name,
			Msg:     "Failed to load " + name + ": " + e.Error(),
		}
	}
	d := &DLL{
		Name:   name,
		Handle: Handle(h),
	}
	return d, nil
}

// MustLoadDLL is like LoadDLL but panics if load operation failes.
func MustLoadDLL(name string) *DLL {
	d, e := LoadDLL(name)
	if e != nil {
		panic(e)
	}
	return d
}

// FindProc searches DLL d for procedure named name and returns *Proc
// if found. It returns an error if search fails.
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
	namep, err := BytePtrFromString(name)
	if err != nil {
		return nil, err
	}
	a, e := getprocaddress(uintptr(d.Handle), namep)
	if e != 0 {
		return nil, &DLLError{
			Err:     e,
			ObjName: name,
			Msg:     "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
		}
	}
	p := &Proc{
		Dll:  d,
		Name: name,
		addr: a,
	}
	return p, nil
}

// MustFindProc is like FindProc but panics if search fails.
func (d *DLL) MustFindProc(name string) *Proc {
	p, e := d.FindProc(name)
	if e != nil {
		panic(e)
	}
	return p
}

// Release unloads DLL d from memory.
func (d *DLL) Release() (err error) {
	return FreeLibrary(d.Handle)
}

// A Proc implements access to a procedure inside a DLL.
type Proc struct {
	Dll  *DLL
	Name string
	addr uintptr
}

// Addr returns the address of the procedure represented by p.
// The return value can be passed to Syscall to run the procedure.
func (p *Proc) Addr() uintptr {
	return p.addr
}

// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
// are supplied.
//
// The returned error is always non-nil, constructed from the result of GetLastError.
// Callers must inspect the primary return value to decide whether an error occurred
// (according to the semantics of the specific function being called) before consulting
// the error. The error will be guaranteed to contain syscall.Errno.
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
	switch len(a) {
	case 0:
		return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
	case 1:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
	case 2:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
	case 3:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
	case 4:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
	case 5:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
	case 6:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
	case 7:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
	case 8:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
	case 9:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
	case 10:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
	case 11:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
	case 12:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
	case 13:
		return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
	case 14:
		return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
	case 15:
		return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
	default:
		panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
	}
	return
}

// A LazyDLL implements access to a single DLL.
// It will delay the load of the DLL until the first
// call to its Handle method or to one of its
// LazyProc's Addr method.
type LazyDLL struct {
	mu   sync.Mutex
	dll  *DLL // non nil once DLL is loaded
	Name string
}

// Load loads DLL file d.Name into memory. It returns an error if fails.
// Load will not try to load DLL, if it is already loaded into memory.
func (d *LazyDLL) Load() error {
	// Non-racy version of:
	// if d.dll == nil {
	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
		d.mu.Lock()
		defer d.mu.Unlock()
		if d.dll == nil {
			dll, e := LoadDLL(d.Name)
			if e != nil {
				return e
			}
			// Non-racy version of:
			// d.dll = dll
			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
		}
	}
	return nil
}

// mustLoad is like Load but panics if search fails.
func (d *LazyDLL) mustLoad() {
	e := d.Load()
	if e != nil {
		panic(e)
	}
}

// Handle returns d's module handle.
func (d *LazyDLL) Handle() uintptr {
	d.mustLoad()
	return uintptr(d.dll.Handle)
}

// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
func (d *LazyDLL) NewProc(name string) *LazyProc {
	return &LazyProc{l: d, Name: name}
}

// NewLazyDLL creates new LazyDLL associated with DLL file.
func NewLazyDLL(name string) *LazyDLL {
	return &LazyDLL{Name: name}
}

// A LazyProc implements access to a procedure inside a LazyDLL.
// It delays the lookup until the Addr method is called.
type LazyProc struct {
	mu   sync.Mutex
	Name string
	l    *LazyDLL
	proc *Proc
}

// Find searches DLL for procedure named p.Name. It returns
// an error if search fails. Find will not search procedure,
// if it is already found and loaded into memory.
func (p *LazyProc) Find() error {
	// Non-racy version of:
	// if p.proc == nil {
	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
		p.mu.Lock()
		defer p.mu.Unlock()
		if p.proc == nil {
			e := p.l.Load()
			if e != nil {
				return e
			}
			proc, e := p.l.dll.FindProc(p.Name)
			if e != nil {
				return e
			}
			// Non-racy version of:
			// p.proc = proc
			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
		}
	}
	return nil
}

// mustFind is like Find but panics if search fails.
func (p *LazyProc) mustFind() {
	e := p.Find()
	if e != nil {
		panic(e)
	}
}

// Addr returns the address of the procedure represented by p.
// The return value can be passed to Syscall to run the procedure.
func (p *LazyProc) Addr() uintptr {
	p.mustFind()
	return p.proc.Addr()
}

// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
// are supplied.
//
// The returned error is always non-nil, constructed from the result of GetLastError.
// Callers must inspect the primary return value to decide whether an error occurred
// (according to the semantics of the specific function being called) before consulting
// the error. The error will be guaranteed to contain syscall.Errno.
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
	p.mustFind()
	return p.proc.Call(a...)
}
<|endoftext|>


<commit_before>// Copyright 2011 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.

// Parse Plan 9 timezone(2) files.

package time

import (
	"os"
	"strconv"
	"strings"
)

func parseZones(s string) (zt []zonetime) {
	f := strings.Fields(s)
	if len(f) < 4 {
		return
	}

	// standard timezone offset
	o, err := strconv.Atoi(f[1])
	if err != nil {
		return
	}
	std := &zone{name: f[0], utcoff: o, isdst: false}

	// alternate timezone offset
	o, err = strconv.Atoi(f[3])
	if err != nil {
		return
	}
	dst := &zone{name: f[2], utcoff: o, isdst: true}

	// transition time pairs
	f = f[4:]
	for i := 0; i < len(f); i++ {
		z := std
		if i%2 == 0 {
			z = dst
		}
		t, err := strconv.Atoi(f[i])
		if err != nil {
			return nil
		}
		t -= std.utcoff
		zt = append(zt, zonetime{time: int32(t), zone: z})
	}
	return
}

func setupZone() {
	t, err := os.Getenverror("timezone")
	if err != nil {
		// do nothing: use UTC
		return
	}
	zones = parseZones(t)
}

func setupTestingZone() {
	f, err := os.Open("/adm/timezone/US_Pacific")
	if err != nil {
		return
	}
	defer f.Close()
	l, _ := f.Seek(0, 2)
	f.Seek(0, 0)
	buf := make([]byte, l)
	_, err := f.Read(buf)
	if err != nil {
		return
	}
	zones = parseZones(buf)
}
<commit_msg>time: fix Plan 9 build<commit_after>// Copyright 2011 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.

// Parse Plan 9 timezone(2) files.

package time

import (
	"os"
	"strconv"
	"strings"
)

func parseZones(s string) (zt []zonetime) {
	f := strings.Fields(s)
	if len(f) < 4 {
		return
	}

	// standard timezone offset
	o, err := strconv.Atoi(f[1])
	if err != nil {
		return
	}
	std := &zone{name: f[0], utcoff: o, isdst: false}

	// alternate timezone offset
	o, err = strconv.Atoi(f[3])
	if err != nil {
		return
	}
	dst := &zone{name: f[2], utcoff: o, isdst: true}

	// transition time pairs
	f = f[4:]
	for i := 0; i < len(f); i++ {
		z := std
		if i%2 == 0 {
			z = dst
		}
		t, err := strconv.Atoi(f[i])
		if err != nil {
			return nil
		}
		t -= std.utcoff
		zt = append(zt, zonetime{time: int32(t), zone: z})
	}
	return
}

func setupZone() {
	t, err := os.Getenverror("timezone")
	if err != nil {
		// do nothing: use UTC
		return
	}
	zones = parseZones(t)
}

func setupTestingZone() {
	f, err := os.Open("/adm/timezone/US_Pacific")
	if err != nil {
		return
	}
	defer f.Close()
	l, _ := f.Seek(0, 2)
	f.Seek(0, 0)
	buf := make([]byte, l)
	_, err = f.Read(buf)
	if err != nil {
		return
	}
	zones = parseZones(string(buf))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/k0kubun/pp"
)

const (
	httpVer     = "HTTP/1.1"
	headerDelim = ": "
	maxBodyLen  = 1024 * 1024
	serverName  = "LittleHTTP"
	serverVer   = "1.0"
	usage       = "Usage: %s [-port=n] [-chroot -user=u -group=g] [-debug] <docroot>\n"
)

// HTTPHeaderField represents an HTTP header field.
type HTTPHeaderField map[string]string

// HTTPRequest represents an HTTP request.
type HTTPRequest struct {
	method string
	path   string
	ver    float64
	header HTTPHeaderField
	body   []byte
	length int64
}

type option struct {
	debug  bool
	chroot bool
	user   string
	group  string
	port   int
}

type logger interface {
	debug(format string, arg ...interface{})
	err(format string, arg ...interface{})
}

type httpLogger struct {
	debugMode bool
}

func newLogger(debugMode bool) *httpLogger {
	return &httpLogger{debugMode: debugMode}
}

func (l *httpLogger) debug(format string, arg ...interface{}) {
	if !l.debugMode {
		return
	}

	_, _ = pp.Fprintf(os.Stderr, format, arg...)
}

func (l *httpLogger) err(format string, arg ...interface{}) {
	_, _ = fmt.Fprintf(os.Stderr, format, arg...)
}

var log logger

func main() {
	opt := &option{}
	flag.BoolVar(&opt.debug, "debug", false, "start on debug mode")
	flag.BoolVar(&opt.chroot, "chroot", false, "change root directory")
	flag.StringVar(&opt.user, "user", "user", "user")
	flag.StringVar(&opt.group, "group", "group", "group")
	flag.IntVar(&opt.port, "port", 8080, "port")
	flag.Parse()

	args := flag.Args()

	log = newLogger(opt.debug)
	log.debug("%v\n", opt)

	if len(args) != 1 {
		fmt.Fprintf(os.Stderr, usage, os.Args[0])
		return
	}

	// TODO: installSignalHandlers()

	docroot := args[0]

	server, err := listenSocket(opt.port)
	if err != nil {
		perror(err)
		return
	}

	log.debug("server fd: %v\n", server)

	serverMain(server, docroot)
}

const maxBacklog = 5

func listenSocket(port int) (int, error) {
	sock, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
	if err != nil {
		return 0, fmt.Errorf("socket() failed: %v", err)
	}

	log.debug("sock: %v\n", sock)

	sa := &syscall.SockaddrInet4{
		Port: port,
		Addr: [4]byte{127, 0, 0, 1},
	}

	log.debug("socket addr: %v\n", sa)

	if e := syscall.Bind(sock, sa); e != nil {
		return 0, fmt.Errorf("bind(%v, %v) failed: %v", sock, sa, err)
	}

	if e := syscall.Listen(sock, maxBacklog); e != nil {
		return 0, fmt.Errorf("listen(%v, %v) failed: %v", sock, maxBacklog, err)
	}

	return sock, nil
}

func serverMain(server int, docroot string) {
	for {
		sock, _, err := syscall.Accept(server)
		if err != nil {
			log.err("accept(%v) failed: %v\n", server, err)
		}

		log.debug("accept %v\n", sock)

		go func(sock int) {
			s := os.NewFile(uintptr(sock), "socket")

			if e := service(s, s, docroot); e != nil {
				log.err("service() failed: %v\n", e)
			}
		}(sock)
	}
}

func service(in, out *os.File, docroot string) error {
	req, err := readRequest(in)
	if err != nil {
		return fmt.Errorf("readRequest(%v) failed: %v", in, err)
	}

	err = respondTo(req, out, docroot)
	if err != nil {
		return fmt.Errorf("readTo(%v, %v, %v) failed: %v", req, out, docroot, err)
	}

	return nil
}

func readRequest(in *os.File) (*HTTPRequest, error) {
	r := bufio.NewReader(in)

	// read request line
	line, err := r.ReadString('\n')
	if err == io.EOF {
		return nil, fmt.Errorf("failed to read request: EOF")
	}

	log.debug("req header: %v\n", line)

	// parse request line to HTTPRequest
	req, err := parseRequestLine(line)
	if err != nil {
		return nil, fmt.Errorf("failed to read request: %v", err)
	}

	// iterate to read request header fields
	h := make(HTTPHeaderField)
	for {
		line, err := r.ReadString('\n')
		// finish reading if EOF or empty line
		if line == "\n" || line == "\r\n" {
			break
		}

		// parse header field
		key, val, err := parseHeaderField(line)
		if err != nil {
			return nil, fmt.Errorf("failed to read request: %v", err)
		}

		h[key] = val
	}
	req.header = h

	// set content length
	// TODO: do this in constructor
	l, err := req.contentLength()
	if err != nil {
		return nil, fmt.Errorf("failed to parse content length: %v", err)
	}
	req.length = l

	if req.length == 0 {
		return req, nil
	}

	if req.length > maxBodyLen {
		return nil, fmt.Errorf("request body too long: %v", req.length)
	}

	// set content body
	// TODO: do this in constructor
	b := make([]byte, req.length)
	if _, e := r.Read(b); e != nil {
		return nil, fmt.Errorf("failed to read request body: %v", b)
	}
	req.body = b

	return req, err
}

func parseRequestLine(line string) (*HTTPRequest, error) {
	// trim trailing \r, \n
	line = strings.Trim(line, "\r\n")

	// split request line
	p := strings.Split(line, " ")
	if len(p) != 3 { // METHOD Request-URI HTTP-Version (RFC2616)
		return nil, fmt.Errorf("parse error on request line: %v", line)
	}

	// check supported HTTP version
	if p[2] != httpVer {
		return nil, fmt.Errorf("not supported HTTP version: %v", p[2])
	}

	ver, err := parseHTTPVer(p[2])
	if err != nil {
		return nil, fmt.Errorf("invalid HTTP version: %v", p[2])
	}

	// p consists of ["METHOD", "/path/to/file", "HTTP/ver"]
	req := &HTTPRequest{
		method: strings.ToUpper(p[0]), // HTTP method is upper case
		path:   p[1],
		ver:    ver,
	}

	return req, nil
}

func parseHTTPVer(ver string) (float64, error) {
	l := len("HTTP/")
	return strconv.ParseFloat(ver[l:], 64)
}

// parseHeaderField parses request header to (key, val, err).
func parseHeaderField(line string) (key, val string, err error) {
	// trim trailing \r, \n
	line = strings.Trim(line, "\r\n")

	// split header field
	p := strings.Split(line, headerDelim)
	if len(p) != 2 { // key:value style
		err = fmt.Errorf("parse error on request header field: %v", line)
		return
	}

	key, val = p[0], p[1]
	return
}

func (req *HTTPRequest) contentLength() (int64, error) {
	key := "Content-Length"

	val, err := req.headerValue(key)
	if err != nil {
		return 0, nil
	}

	l, e := strconv.ParseInt(val, 10, 64)
	if e != nil {
		return 0, fmt.Errorf("parse error on ``%v: %v`: %v", key, val, e)
	}

	return l, nil
}

func (req *HTTPRequest) headerValue(name string) (string, error) {
	val, exists := req.header[name]
	if !exists {
		return "", fmt.Errorf("header `%v` not exist", name)
	}

	return val, nil
}

func respondTo(req *HTTPRequest, out *os.File, docroot string) error {
	var err error

	switch req.method {
	case "GET", "HEAD":
		err = doFileResponse(req, out, docroot)
	case "POST":
		methodNotAllowed(req, out)
	default:
		notImplemented(req, out)
	}

	return err
}

func doFileResponse(req *HTTPRequest, out *os.File, docroot string) error {
	fi, err := getFileInfo(docroot, req.path)
	if err != nil {
		notFound(req, out)
		return fmt.Errorf("getFileInfo(%s, %s) failed: %v", docroot, req.path, err)
	}

	outputCommonHeaderFields(req, out, "200 OK")
	fmt.Fprintf(out, "Content-Length: %d\r\n", fi.Size())
	fmt.Fprintf(out, "Content-Type: %s\r\n\r\n", guessContentType(fi))

	// HEAD method responses only headers
	if req.method == "HEAD" {
		return nil
	}

	// read file contents
	fspath := buildFSPath(docroot, req.path)
	err = printFileContents(fspath, out)
	if err != nil {
		return fmt.Errorf("doFileResponse() failed: %v", err)
	}

	return nil
}

func printFileContents(path string, out *os.File) error {
	// Note: suppose the size of the requested file is small
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return fmt.Errorf("failed to read file %s: %v", path, err)
	}

	if _, e := out.Write(buf); e != nil {
		return fmt.Errorf("failed to write: %v", err)
	}

	return nil
}

func notFound(req *HTTPRequest, out *os.File) {
	outputCommonHeaderFields(req, out, "404 Not Found")
	fmt.Fprintf(out, "Content-Type: text/plain\r\n\r\n")
	fmt.Fprintf(out, "File not found\r\n")
}

func methodNotAllowed(req *HTTPRequest, out *os.File) {
	outputCommonHeaderFields(req, out, "405 Method Not Allowed")
	fmt.Fprintf(out, "Content-Type: text/plain\r\n\r\n")
	fmt.Fprintf(out, "The requested method %s is not allowed\r\n", req.method)
}

func notImplemented(req *HTTPRequest, out *os.File) {
	outputCommonHeaderFields(req, out, "501 Not Implemented")
	fmt.Fprintf(out, "Content-Type: text/plain\r\n\r\n")
	fmt.Fprintf(out, "The requested method %s is not implemented\r\n", req.method)
}

func outputCommonHeaderFields(req *HTTPRequest, out *os.File, status string) {
	fmt.Fprintf(out, "%s %s\r\n", httpVer, status)
	fmt.Fprintf(out, "Date: %s\r\n", time.Now().Format(time.RFC1123))
	fmt.Fprintf(out, "Server: %s/%s\r\n", serverName, serverVer)
	fmt.Fprintf(out, "Connection: close\r\n")
}

func guessContentType(fi os.FileInfo) string {
	return "text/plain"
}

func getFileInfo(docroot, urlpath string) (os.FileInfo, error) {
	path := buildFSPath(docroot, urlpath)
	return os.Lstat(path)
}

func buildFSPath(docroot, urlpath string) string {
	return fmt.Sprintf("%s/%s", docroot, urlpath)
}

func installSignalHandlers() {
	// TODO
	return
}

func perror(err error) {
	fmt.Fprintf(os.Stderr, "[error] %v\n", err)
}
<commit_msg>httpd.go: fix to forget to close socket discriptor<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/k0kubun/pp"
)

const (
	httpVer     = "HTTP/1.1"
	headerDelim = ": "
	maxBodyLen  = 1024 * 1024
	serverName  = "LittleHTTP"
	serverVer   = "1.0"
	usage       = "Usage: %s [-port=n] [-chroot -user=u -group=g] [-debug] <docroot>\n"
)

// HTTPHeaderField represents an HTTP header field.
type HTTPHeaderField map[string]string

// HTTPRequest represents an HTTP request.
type HTTPRequest struct {
	method string
	path   string
	ver    float64
	header HTTPHeaderField
	body   []byte
	length int64
}

type option struct {
	debug  bool
	chroot bool
	user   string
	group  string
	port   int
}

type logger interface {
	debug(format string, arg ...interface{})
	err(format string, arg ...interface{})
}

type httpLogger struct {
	debugMode bool
}

func newLogger(debugMode bool) *httpLogger {
	return &httpLogger{debugMode: debugMode}
}

func (l *httpLogger) debug(format string, arg ...interface{}) {
	if !l.debugMode {
		return
	}

	_, _ = pp.Fprintf(os.Stderr, format, arg...)
}

func (l *httpLogger) err(format string, arg ...interface{}) {
	_, _ = fmt.Fprintf(os.Stderr, format, arg...)
}

var log logger

func main() {
	opt := &option{}
	flag.BoolVar(&opt.debug, "debug", false, "start on debug mode")
	flag.BoolVar(&opt.chroot, "chroot", false, "change root directory")
	flag.StringVar(&opt.user, "user", "user", "user")
	flag.StringVar(&opt.group, "group", "group", "group")
	flag.IntVar(&opt.port, "port", 8080, "port")
	flag.Parse()

	args := flag.Args()

	log = newLogger(opt.debug)
	log.debug("%v\n", opt)

	if len(args) != 1 {
		fmt.Fprintf(os.Stderr, usage, os.Args[0])
		return
	}

	// TODO: installSignalHandlers()

	docroot := args[0]

	server, err := listenSocket(opt.port)
	if err != nil {
		perror(err)
		return
	}

	log.debug("server fd: %v\n", server)

	serverMain(server, docroot)
}

const maxBacklog = 5

func listenSocket(port int) (int, error) {
	sock, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
	if err != nil {
		return 0, fmt.Errorf("socket() failed: %v", err)
	}

	log.debug("sock: %v\n", sock)

	sa := &syscall.SockaddrInet4{
		Port: port,
		Addr: [4]byte{127, 0, 0, 1},
	}

	log.debug("socket addr: %v\n", sa)

	if e := syscall.Bind(sock, sa); e != nil {
		_ = syscall.Close(sock)
		return 0, fmt.Errorf("bind to %v:%v failed: %v", sa.Addr, sa.Port, err)
	}

	if e := syscall.Listen(sock, maxBacklog); e != nil {
		_ = syscall.Close(sock)
		return 0, fmt.Errorf("listen(%v, %v) failed: %v", sock, maxBacklog, err)
	}

	return sock, nil
}

func serverMain(server int, docroot string) {
	for {
		sock, _, err := syscall.Accept(server)
		if err != nil {
			log.err("accept(%v) failed: %v\n", server, err)
			continue
		}

		log.debug("accept %v\n", sock)

		go func(sock int) {
			s := os.NewFile(uintptr(sock), "socket")

			if e := service(s, s, docroot); e != nil {
				log.err("service() failed: %v\n", e)
			}

			if e := syscall.Close(sock); e != nil {
				log.err("close(%v) failed: %v\n", sock, e)
			}
		}(sock)
	}
}

func service(in, out *os.File, docroot string) error {
	req, err := readRequest(in)
	if err != nil {
		return fmt.Errorf("readRequest() failed: %v", err)
	}

	err = respondTo(req, out, docroot)
	if err != nil {
		return fmt.Errorf("respondTo() failed: %v", err)
	}

	return nil
}

func readRequest(in *os.File) (*HTTPRequest, error) {
	r := bufio.NewReader(in)

	// read request line
	line, err := r.ReadString('\n')
	if err == io.EOF {
		return nil, nil
	}

	log.debug("req header: %v\n", line)

	// parse request line to HTTPRequest
	req, err := parseRequestLine(line)
	if err != nil {
		return nil, fmt.Errorf("failed to read request: %v", err)
	}

	// iterate to read request header fields
	h := make(HTTPHeaderField)
	for {
		line, err := r.ReadString('\n')
		// finish reading if EOF or empty line
		if line == "\n" || line == "\r\n" {
			break
		}

		// parse header field
		key, val, err := parseHeaderField(line)
		if err != nil {
			return nil, fmt.Errorf("failed to read request: %v", err)
		}

		h[key] = val
	}
	req.header = h

	// set content length
	// TODO: do this in constructor
	l, err := req.contentLength()
	if err != nil {
		return nil, fmt.Errorf("failed to parse content length: %v", err)
	}
	req.length = l

	if req.length == 0 {
		return req, nil
	}

	if req.length > maxBodyLen {
		return nil, fmt.Errorf("request body too long: %v", req.length)
	}

	// set content body
	// TODO: do this in constructor
	b := make([]byte, req.length)
	if _, e := r.Read(b); e != nil {
		return nil, fmt.Errorf("failed to read request body: %v", b)
	}
	req.body = b

	return req, err
}

func parseRequestLine(line string) (*HTTPRequest, error) {
	// trim trailing \r, \n
	line = strings.Trim(line, "\r\n")

	// split request line
	p := strings.Split(line, " ")
	if len(p) != 3 { // METHOD Request-URI HTTP-Version (RFC2616)
		return nil, fmt.Errorf("parse error on request line: %v", line)
	}

	// check supported HTTP version
	if p[2] != httpVer {
		return nil, fmt.Errorf("not supported HTTP version: %v", p[2])
	}

	ver, err := parseHTTPVer(p[2])
	if err != nil {
		return nil, fmt.Errorf("invalid HTTP version: %v", p[2])
	}

	// p consists of ["METHOD", "/path/to/file", "HTTP/ver"]
	req := &HTTPRequest{
		method: strings.ToUpper(p[0]), // HTTP method is upper case
		path:   p[1],
		ver:    ver,
	}

	return req, nil
}

func parseHTTPVer(ver string) (float64, error) {
	l := len("HTTP/")
	return strconv.ParseFloat(ver[l:], 64)
}

// parseHeaderField parses request header to (key, val, err).
func parseHeaderField(line string) (key, val string, err error) {
	// trim trailing \r, \n
	line = strings.Trim(line, "\r\n")

	// split header field
	p := strings.Split(line, headerDelim)
	if len(p) != 2 { // key:value style
		err = fmt.Errorf("parse error on request header field: %v", line)
		return
	}

	key, val = p[0], p[1]
	return
}

func (req *HTTPRequest) contentLength() (int64, error) {
	key := "Content-Length"

	val, err := req.headerValue(key)
	if err != nil {
		return 0, nil
	}

	l, e := strconv.ParseInt(val, 10, 64)
	if e != nil {
		return 0, fmt.Errorf("parse error on ``%v: %v`: %v", key, val, e)
	}

	return l, nil
}

func (req *HTTPRequest) headerValue(name string) (string, error) {
	val, exists := req.header[name]
	if !exists {
		return "", fmt.Errorf("header `%v` not exist", name)
	}

	return val, nil
}

func respondTo(req *HTTPRequest, out *os.File, docroot string) error {
	var err error

	switch req.method {
	case "GET", "HEAD":
		err = doFileResponse(req, out, docroot)
	case "POST":
		methodNotAllowed(req, out)
	default:
		notImplemented(req, out)
	}

	return err
}

func doFileResponse(req *HTTPRequest, out *os.File, docroot string) error {
	fi, err := getFileInfo(docroot, req.path)
	if err != nil {
		notFound(req, out)
		return fmt.Errorf("getFileInfo(%s, %s) failed: %v", docroot, req.path, err)
	}

	outputCommonHeaderFields(req, out, "200 OK")
	fmt.Fprintf(out, "Content-Length: %d\r\n", fi.Size())
	fmt.Fprintf(out, "Content-Type: %s\r\n\r\n", guessContentType(fi))

	// HEAD method responses only headers
	if req.method == "HEAD" {
		return nil
	}

	// read file contents
	fspath := buildFSPath(docroot, req.path)
	err = printFileContents(fspath, out)
	if err != nil {
		return fmt.Errorf("doFileResponse() failed: %v", err)
	}

	return nil
}

func printFileContents(path string, out *os.File) error {
	// Note: suppose the size of the requested file is small
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return fmt.Errorf("failed to read file %s: %v", path, err)
	}

	if _, e := out.Write(buf); e != nil {
		return fmt.Errorf("failed to write: %v", err)
	}

	return nil
}

func notFound(req *HTTPRequest, out *os.File) {
	outputCommonHeaderFields(req, out, "404 Not Found")
	fmt.Fprintf(out, "Content-Type: text/plain\r\n\r\n")
	fmt.Fprintf(out, "File not found\r\n")
}

func methodNotAllowed(req *HTTPRequest, out *os.File) {
	outputCommonHeaderFields(req, out, "405 Method Not Allowed")
	fmt.Fprintf(out, "Content-Type: text/plain\r\n\r\n")
	fmt.Fprintf(out, "The requested method %s is not allowed\r\n", req.method)
}

func notImplemented(req *HTTPRequest, out *os.File) {
	outputCommonHeaderFields(req, out, "501 Not Implemented")
	fmt.Fprintf(out, "Content-Type: text/plain\r\n\r\n")
	fmt.Fprintf(out, "The requested method %s is not implemented\r\n", req.method)
}

func outputCommonHeaderFields(req *HTTPRequest, out *os.File, status string) {
	fmt.Fprintf(out, "%s %s\r\n", httpVer, status)
	fmt.Fprintf(out, "Date: %s\r\n", time.Now().Format(time.RFC1123))
	fmt.Fprintf(out, "Server: %s/%s\r\n", serverName, serverVer)
	fmt.Fprintf(out, "Connection: close\r\n")
}

func guessContentType(fi os.FileInfo) string {
	return "text/plain"
}

func getFileInfo(docroot, urlpath string) (os.FileInfo, error) {
	path := buildFSPath(docroot, urlpath)
	return os.Lstat(path)
}

func buildFSPath(docroot, urlpath string) string {
	return fmt.Sprintf("%s/%s", docroot, urlpath)
}

func installSignalHandlers() {
	// TODO
	return
}

func perror(err error) {
	fmt.Fprintf(os.Stderr, "[error] %v\n", err)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Tigera, Inc. All rights reserved.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package resourcemgr

import (
	"context"

	api "github.com/projectcalico/libcalico-go/lib/apis/v3"
	client "github.com/projectcalico/libcalico-go/lib/clientv3"
	"github.com/projectcalico/libcalico-go/lib/options"
)

func init() {
	registerResource(
		api.NewWorkloadEndpoint(),
		api.NewWorkloadEndpointList(),
		true,
		[]string{"workloadendpoint", "workloadendpoints", "wep", "weps"},
		[]string{"NAME", "NODE", "WORKLOAD", "INTERFACE"},
		[]string{"NAME", "NODE", "WORKLOAD", "NETWORKS", "INTERFACE", "PROFILES", "NATS"},
		// NAMESPACE may be prepended in GrabTableTemplate so needs to remain in the map below
		map[string]string{
			"NAME":         "{{.ObjectMeta.Name}}",
			"NAMESPACE":    "{{.ObjectMeta.Namespace}}",
			"NODE":         "{{.Spec.Node}}",
			"ORCHESTRATOR": "{{.Spec.Orchestrator}}",
			"WORKLOAD":     "{{.Spec.Workload}}",
			"NETWORKS":     "{{join .Spec.IPNetworks \",\"}}",
			"NATS":         "{{join .Spec.IPNATs \",\"}}",
			"PROFILES":     "{{join .Spec.Profiles \",\"}}",
			"INTERFACE":    "{{.Spec.InterfaceName}}",
		},
		func(ctx context.Context, client client.Interface, resource ResourceObject) (ResourceObject, error) {
			r := resource.(*api.WorkloadEndpoint)
			return client.WorkloadEndpoints().Create(ctx, r, options.SetOptions{})
		},
		func(ctx context.Context, client client.Interface, resource ResourceObject) (ResourceObject, error) {
			r := resource.(*api.WorkloadEndpoint)
			return client.WorkloadEndpoints().Update(ctx, r, options.SetOptions{})
		},
		func(ctx context.Context, client client.Interface, resource ResourceObject) (ResourceObject, error) {
			r := resource.(*api.WorkloadEndpoint)
			return client.WorkloadEndpoints().Delete(ctx, r.Namespace, r.Name, options.DeleteOptions{ResourceVersion: r.ResourceVersion})
		},
		func(ctx context.Context, client client.Interface, resource ResourceObject) (ResourceObject, error) {
			r := resource.(*api.WorkloadEndpoint)
			return client.WorkloadEndpoints().Get(ctx, r.Namespace, r.Name, options.GetOptions{ResourceVersion: r.ResourceVersion})
		},
		func(ctx context.Context, client client.Interface, resource ResourceObject) (ResourceListObject, error) {
			r := resource.(*api.WorkloadEndpoint)
			return client.WorkloadEndpoints().List(ctx, options.ListOptions{ResourceVersion: r.ResourceVersion, Namespace: r.Namespace, Name: r.Name})
		},
	)
}
<commit_msg>Update WEP output to hide long name, show pod name<commit_after>// Copyright (c) 2016-2017 Tigera, Inc. All rights reserved.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package resourcemgr

import (
	"context"

	api "github.com/projectcalico/libcalico-go/lib/apis/v3"
	client "github.com/projectcalico/libcalico-go/lib/clientv3"
	"github.com/projectcalico/libcalico-go/lib/options"
)

func init() {
	registerResource(
		api.NewWorkloadEndpoint(),
		api.NewWorkloadEndpointList(),
		true,
		[]string{"workloadendpoint", "workloadendpoints", "wep", "weps"},
		[]string{"WORKLOAD", "NODE", "NETWORKS", "INTERFACE"},
		[]string{"NAME", "WORKLOAD", "NODE", "NETWORKS", "INTERFACE", "PROFILES", "NATS"},
		// NAMESPACE may be prepended in GrabTableTemplate so needs to remain in the map below
		map[string]string{
			"NAME":         "{{.ObjectMeta.Name}}",
			"NAMESPACE":    "{{.ObjectMeta.Namespace}}",
			"NODE":         "{{.Spec.Node}}",
			"ORCHESTRATOR": "{{.Spec.Orchestrator}}",
			"WORKLOAD":     "{{if .Spec.Workload}}{{.Spec.Workload}}{{else}}{{.Spec.Pod}}{{end}}",
			"NETWORKS":     "{{join .Spec.IPNetworks \",\"}}",
			"NATS":         "{{join .Spec.IPNATs \",\"}}",
			"PROFILES":     "{{join .Spec.Profiles \",\"}}",
			"INTERFACE":    "{{.Spec.InterfaceName}}",
		},
		func(ctx context.Context, client client.Interface, resource ResourceObject) (ResourceObject, error) {
			r := resource.(*api.WorkloadEndpoint)
			return client.WorkloadEndpoints().Create(ctx, r, options.SetOptions{})
		},
		func(ctx context.Context, client client.Interface, resource ResourceObject) (ResourceObject, error) {
			r := resource.(*api.WorkloadEndpoint)
			return client.WorkloadEndpoints().Update(ctx, r, options.SetOptions{})
		},
		func(ctx context.Context, client client.Interface, resource ResourceObject) (ResourceObject, error) {
			r := resource.(*api.WorkloadEndpoint)
			return client.WorkloadEndpoints().Delete(ctx, r.Namespace, r.Name, options.DeleteOptions{ResourceVersion: r.ResourceVersion})
		},
		func(ctx context.Context, client client.Interface, resource ResourceObject) (ResourceObject, error) {
			r := resource.(*api.WorkloadEndpoint)
			return client.WorkloadEndpoints().Get(ctx, r.Namespace, r.Name, options.GetOptions{ResourceVersion: r.ResourceVersion})
		},
		func(ctx context.Context, client client.Interface, resource ResourceObject) (ResourceListObject, error) {
			r := resource.(*api.WorkloadEndpoint)
			return client.WorkloadEndpoints().List(ctx, options.ListOptions{ResourceVersion: r.ResourceVersion, Namespace: r.Namespace, Name: r.Name})
		},
	)
}
<|endoftext|>


<commit_before>package terraform

import (
	"fmt"

	"github.com/hashicorp/hcl2/hcl"
	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/config/configschema"
	"github.com/hashicorp/terraform/configs"
	"github.com/hashicorp/terraform/tfdiags"
	"github.com/zclconf/go-cty/cty"
	"github.com/zclconf/go-cty/cty/gocty"
)

// EvalValidateCount is an EvalNode implementation that validates
// the count of a resource.
type EvalValidateCount struct {
	Resource *configs.Resource
}

// TODO: test
func (n *EvalValidateCount) Eval(ctx EvalContext) (interface{}, error) {
	var diags tfdiags.Diagnostics
	var count int
	var err error

	val, valDiags := ctx.EvaluateExpr(n.Resource.Count, cty.Number, nil)
	diags = diags.Append(valDiags)
	if valDiags.HasErrors() {
		goto RETURN
	}
	if val.IsNull() || !val.IsKnown() {
		goto RETURN
	}

	err = gocty.FromCtyValue(val, &count)
	if err != nil {
		// The EvaluateExpr call above already guaranteed us a number value,
		// so if we end up here then we have something that is out of range
		// for an int, and the error message will include a description of
		// the valid range.
		rawVal := val.AsBigFloat()
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  "Invalid count value",
			Detail:   fmt.Sprintf("The number %s is not a valid count value: %s.", rawVal, err),
			Subject:  n.Resource.Count.Range().Ptr(),
		})
	} else if count < 0 {
		rawVal := val.AsBigFloat()
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  "Invalid count value",
			Detail:   fmt.Sprintf("The number %s is not a valid count value: count must not be negative.", rawVal),
			Subject:  n.Resource.Count.Range().Ptr(),
		})
	}

RETURN:
	return nil, diags.NonFatalErr()
}

// EvalValidateProvider is an EvalNode implementation that validates
// a provider configuration.
type EvalValidateProvider struct {
	Addr     addrs.ProviderConfig
	Provider *ResourceProvider
	Config   *configs.Provider
}

func (n *EvalValidateProvider) Eval(ctx EvalContext) (interface{}, error) {
	var diags tfdiags.Diagnostics
	provider := *n.Provider
	config := n.Config

	if n.Config == nil {
		// Nothing to validate, then.
		return nil, nil
	}

	schema, err := provider.GetSchema(&ProviderSchemaRequest{})
	if err != nil {
		diags = diags.Append(err)
		return nil, diags.NonFatalErr()
	}

	configSchema := schema.Provider
	configBody := buildProviderConfig(ctx, n.Addr, config.Config)
	configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, addrs.NoKey)
	diags = diags.Append(evalDiags)
	if evalDiags.HasErrors() {
		return nil, diags.NonFatalErr()
	}

	// The provider API expects our legacy ResourceConfig type, so we'll need
	// to shim here.
	rc := NewResourceConfigShimmed(configVal, configSchema)

	warns, errs := provider.Validate(rc)
	if len(warns) == 0 && len(errs) == 0 {
		return nil, nil
	}

	// FIXME: Once provider.Validate itself returns diagnostics, just
	// return diags.NonFatalErr() immediately here.
	for _, warn := range warns {
		diags = diags.Append(tfdiags.SimpleWarning(warn))
	}
	for _, err := range errs {
		diags = diags.Append(err)
	}

	return nil, diags.NonFatalErr()
}

// EvalValidateProvisioner is an EvalNode implementation that validates
// the configuration of a provisioner belonging to a resource.
type EvalValidateProvisioner struct {
	ResourceAddr addrs.ResourceInstance
	Provisioner  *ResourceProvisioner
	Schema       **configschema.Block
	Config       *configs.Provisioner
	ConnConfig   *configs.Connection
}

func (n *EvalValidateProvisioner) Eval(ctx EvalContext) (interface{}, error) {
	provisioner := *n.Provisioner
	config := *n.Config
	schema := *n.Schema

	var warns []string
	var errs []error

	var diags tfdiags.Diagnostics

	{
		// Validate the provisioner's own config first

		configVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, n.ResourceAddr, n.ResourceAddr.Key)
		diags = diags.Append(configDiags)
		if configDiags.HasErrors() {
			return nil, diags.Err()
		}

		// The provisioner API still uses our legacy ResourceConfig type, so
		// we need to shim it.
		legacyRC := NewResourceConfigShimmed(configVal, schema)

		w, e := provisioner.Validate(legacyRC)
		warns = append(warns, w...)
		errs = append(errs, e...)

		// FIXME: Once the provisioner API itself returns diagnostics, just
		// return diags.NonFatalErr() here.
		for _, warn := range warns {
			diags = diags.Append(tfdiags.SimpleWarning(warn))
		}
		for _, err := range errs {
			diags = diags.Append(err)
		}
	}

	{
		// Now validate the connection config, which might either be from
		// the provisioner block itself or inherited from the resource's
		// shared connection info.
		connDiags := n.validateConnConfig(ctx, n.ConnConfig, n.ResourceAddr)
		diags = diags.Append(connDiags)
	}

	return nil, diags.NonFatalErr()
}

func (n *EvalValidateProvisioner) validateConnConfig(ctx EvalContext, config *configs.Connection, self addrs.Referenceable) tfdiags.Diagnostics {
	// We can't comprehensively validate the connection config since its
	// final structure is decided by the communicator and we can't instantiate
	// that until we have a complete instance state. However, we *can* catch
	// configuration keys that are not valid for *any* communicator, catching
	// typos early rather than waiting until we actually try to run one of
	// the resource's provisioners.

	var diags tfdiags.Diagnostics

	// We evaluate here just by evaluating the block and returning any
	// diagnostics we get, since evaluation alone is enough to check for
	// extraneous arguments and incorrectly-typed arguments.
	_, _, configDiags := ctx.EvaluateBlock(config.Config, connectionBlockSupersetSchema, self, n.ResourceAddr.Key)
	diags = diags.Append(configDiags)

	return diags
}

// connectionBlockSupersetSchema is a schema representing the superset of all
// possible arguments for "connection" blocks across all supported connection
// types.
//
// This currently lives here because we've not yet updated our communicator
// subsystem to be aware of schema itself. Once that is done, we can remove
// this and use a type-specific schema from the communicator to validate
// exactly what is expected for a given connection type.
var connectionBlockSupersetSchema = &configschema.Block{
	Attributes: map[string]*configschema.Attribute{
		"type": {
			Type:     cty.String,
			Required: true,
		},

		// Common attributes for both connection types
		"user": {
			Type:     cty.String,
			Required: false,
		},
		"password": {
			Type:     cty.String,
			Required: false,
		},
		"host": {
			Type:     cty.String,
			Required: false,
		},
		"port": {
			Type:     cty.Number,
			Required: false,
		},
		"timeout": {
			Type:     cty.String,
			Required: false,
		},
		"script_path": {
			Type:     cty.String,
			Required: false,
		},

		// For type=ssh only (enforced in ssh communicator)
		"private_key": {
			Type:     cty.String,
			Required: false,
		},
		"host_key": {
			Type:     cty.String,
			Required: false,
		},
		"agent": {
			Type:     cty.Bool,
			Required: false,
		},
		"agent_identity": {
			Type:     cty.String,
			Required: false,
		},
		"bastion_host": {
			Type:     cty.String,
			Required: false,
		},
		"bastion_host_key": {
			Type:     cty.String,
			Required: false,
		},
		"bastion_port": {
			Type:     cty.Number,
			Required: false,
		},
		"bastion_user": {
			Type:     cty.String,
			Required: false,
		},
		"bastion_password": {
			Type:     cty.String,
			Required: false,
		},
		"bastion_private_key": {
			Type:     cty.String,
			Required: false,
		},

		// For type=winrm only (enforced in winrm communicator)
		"https": {
			Type:     cty.Bool,
			Required: false,
		},
		"insecure": {
			Type:     cty.Bool,
			Required: false,
		},
		"cacert": {
			Type:     cty.String,
			Required: false,
		},
		"use_ntlm": {
			Type:     cty.Bool,
			Required: false,
		},
	},
}

// EvalValidateResource is an EvalNode implementation that validates
// the configuration of a resource.
type EvalValidateResource struct {
	Addr           addrs.ResourceInstance
	Provider       *ResourceProvider
	ProviderSchema **ProviderSchema
	Config         *configs.Resource

	// IgnoreWarnings means that warnings will not be passed through. This allows
	// "just-in-time" passes of validation to continue execution through warnings.
	IgnoreWarnings bool

	// ConfigVal, if non-nil, will be updated with the value resulting from
	// evaluating the given configuration body. Since validation is performed
	// very early, this value is likely to contain lots of unknown values,
	// but its type will conform to the schema of the resource type associated
	// with the resource instance being validated.
	ConfigVal *cty.Value
}

func (n *EvalValidateResource) Eval(ctx EvalContext) (interface{}, error) {
	if n.ProviderSchema == nil {
		return nil, fmt.Errorf("EvalValidateResource has nil schema for %s", n.Addr)
	}

	var diags tfdiags.Diagnostics
	provider := *n.Provider
	cfg := *n.Config
	schema := *n.ProviderSchema
	mode := cfg.Mode

	var warns []string
	var errs []error

	// Provider entry point varies depending on resource mode, because
	// managed resources and data resources are two distinct concepts
	// in the provider abstraction.
	switch mode {
	case addrs.ManagedResourceMode:
		schema, exists := schema.ResourceTypes[cfg.Type]
		if !exists {
			diags = diags.Append(&hcl.Diagnostic{
				Severity: hcl.DiagError,
				Summary:  "Invalid resource type",
				Detail:   fmt.Sprintf("The provider %s does not support resource type %q.", cfg.ProviderConfigAddr(), cfg.Type),
				Subject:  &cfg.TypeRange,
			})
			return nil, diags.Err()
		}

		configVal, _, valDiags := ctx.EvaluateBlock(cfg.Config, schema, nil, n.Addr.Key)
		diags = diags.Append(valDiags)
		if valDiags.HasErrors() {
			return nil, diags.Err()
		}

		// The provider API still expects our legacy types, so we must do some
		// shimming here.
		legacyCfg := NewResourceConfigShimmed(configVal, schema)
		warns, errs = provider.ValidateResource(cfg.Type, legacyCfg)

		if n.ConfigVal != nil {
			*n.ConfigVal = configVal
		}

	case addrs.DataResourceMode:
		schema, exists := schema.DataSources[cfg.Type]
		if !exists {
			diags = diags.Append(&hcl.Diagnostic{
				Severity: hcl.DiagError,
				Summary:  "Invalid data source",
				Detail:   fmt.Sprintf("The provider %s does not support data source %q.", cfg.ProviderConfigAddr(), cfg.Type),
				Subject:  &cfg.TypeRange,
			})
			return nil, diags.Err()
		}

		configVal, _, valDiags := ctx.EvaluateBlock(cfg.Config, schema, nil, n.Addr.Key)
		diags = diags.Append(valDiags)
		if valDiags.HasErrors() {
			return nil, diags.Err()
		}

		// The provider API still expects our legacy types, so we must do some
		// shimming here.
		legacyCfg := NewResourceConfigShimmed(configVal, schema)
		warns, errs = provider.ValidateDataSource(cfg.Type, legacyCfg)

		if n.ConfigVal != nil {
			*n.ConfigVal = configVal
		}
	}

	// FIXME: Update the provider API to actually return diagnostics here,
	// and then we can remove all this shimming and use its diagnostics
	// directly.
	for _, warn := range warns {
		diags = diags.Append(tfdiags.SimpleWarning(warn))
	}
	for _, err := range errs {
		diags = diags.Append(err)
	}

	if n.IgnoreWarnings {
		// If we _only_ have warnings then we'll return nil.
		if diags.HasErrors() {
			return nil, diags.NonFatalErr()
		}
		return nil, nil
	} else {
		// We'll return an error if there are any diagnostics at all, even if
		// some of them are warnings.
		return nil, diags.NonFatalErr()
	}
}
<commit_msg>core: Don't crash if EvaluateBlock returns nil during validation<commit_after>package terraform

import (
	"fmt"

	"github.com/hashicorp/hcl2/hcl"
	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/config/configschema"
	"github.com/hashicorp/terraform/configs"
	"github.com/hashicorp/terraform/tfdiags"
	"github.com/zclconf/go-cty/cty"
	"github.com/zclconf/go-cty/cty/gocty"
)

// EvalValidateCount is an EvalNode implementation that validates
// the count of a resource.
type EvalValidateCount struct {
	Resource *configs.Resource
}

// TODO: test
func (n *EvalValidateCount) Eval(ctx EvalContext) (interface{}, error) {
	var diags tfdiags.Diagnostics
	var count int
	var err error

	val, valDiags := ctx.EvaluateExpr(n.Resource.Count, cty.Number, nil)
	diags = diags.Append(valDiags)
	if valDiags.HasErrors() {
		goto RETURN
	}
	if val.IsNull() || !val.IsKnown() {
		goto RETURN
	}

	err = gocty.FromCtyValue(val, &count)
	if err != nil {
		// The EvaluateExpr call above already guaranteed us a number value,
		// so if we end up here then we have something that is out of range
		// for an int, and the error message will include a description of
		// the valid range.
		rawVal := val.AsBigFloat()
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  "Invalid count value",
			Detail:   fmt.Sprintf("The number %s is not a valid count value: %s.", rawVal, err),
			Subject:  n.Resource.Count.Range().Ptr(),
		})
	} else if count < 0 {
		rawVal := val.AsBigFloat()
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  "Invalid count value",
			Detail:   fmt.Sprintf("The number %s is not a valid count value: count must not be negative.", rawVal),
			Subject:  n.Resource.Count.Range().Ptr(),
		})
	}

RETURN:
	return nil, diags.NonFatalErr()
}

// EvalValidateProvider is an EvalNode implementation that validates
// a provider configuration.
type EvalValidateProvider struct {
	Addr     addrs.ProviderConfig
	Provider *ResourceProvider
	Config   *configs.Provider
}

func (n *EvalValidateProvider) Eval(ctx EvalContext) (interface{}, error) {
	var diags tfdiags.Diagnostics
	provider := *n.Provider
	config := n.Config

	if n.Config == nil {
		// Nothing to validate, then.
		return nil, nil
	}

	schema, err := provider.GetSchema(&ProviderSchemaRequest{})
	if err != nil {
		diags = diags.Append(err)
		return nil, diags.NonFatalErr()
	}

	configSchema := schema.Provider
	configBody := buildProviderConfig(ctx, n.Addr, config.Config)
	configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, addrs.NoKey)
	diags = diags.Append(evalDiags)
	if evalDiags.HasErrors() {
		return nil, diags.NonFatalErr()
	}

	// The provider API expects our legacy ResourceConfig type, so we'll need
	// to shim here.
	rc := NewResourceConfigShimmed(configVal, configSchema)

	warns, errs := provider.Validate(rc)
	if len(warns) == 0 && len(errs) == 0 {
		return nil, nil
	}

	// FIXME: Once provider.Validate itself returns diagnostics, just
	// return diags.NonFatalErr() immediately here.
	for _, warn := range warns {
		diags = diags.Append(tfdiags.SimpleWarning(warn))
	}
	for _, err := range errs {
		diags = diags.Append(err)
	}

	return nil, diags.NonFatalErr()
}

// EvalValidateProvisioner is an EvalNode implementation that validates
// the configuration of a provisioner belonging to a resource.
type EvalValidateProvisioner struct {
	ResourceAddr addrs.ResourceInstance
	Provisioner  *ResourceProvisioner
	Schema       **configschema.Block
	Config       *configs.Provisioner
	ConnConfig   *configs.Connection
}

func (n *EvalValidateProvisioner) Eval(ctx EvalContext) (interface{}, error) {
	provisioner := *n.Provisioner
	config := *n.Config
	schema := *n.Schema

	var warns []string
	var errs []error

	var diags tfdiags.Diagnostics

	{
		// Validate the provisioner's own config first

		configVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, n.ResourceAddr, n.ResourceAddr.Key)
		diags = diags.Append(configDiags)
		if configDiags.HasErrors() {
			return nil, diags.Err()
		}

		if configVal == cty.NilVal {
			// Should never happen for a well-behaved EvaluateBlock implementation
			return nil, fmt.Errorf("EvaluateBlock returned nil value")
		}

		// The provisioner API still uses our legacy ResourceConfig type, so
		// we need to shim it.
		legacyRC := NewResourceConfigShimmed(configVal, schema)

		w, e := provisioner.Validate(legacyRC)
		warns = append(warns, w...)
		errs = append(errs, e...)

		// FIXME: Once the provisioner API itself returns diagnostics, just
		// return diags.NonFatalErr() here.
		for _, warn := range warns {
			diags = diags.Append(tfdiags.SimpleWarning(warn))
		}
		for _, err := range errs {
			diags = diags.Append(err)
		}
	}

	{
		// Now validate the connection config, which might either be from
		// the provisioner block itself or inherited from the resource's
		// shared connection info.
		connDiags := n.validateConnConfig(ctx, n.ConnConfig, n.ResourceAddr)
		diags = diags.Append(connDiags)
	}

	return nil, diags.NonFatalErr()
}

func (n *EvalValidateProvisioner) validateConnConfig(ctx EvalContext, config *configs.Connection, self addrs.Referenceable) tfdiags.Diagnostics {
	// We can't comprehensively validate the connection config since its
	// final structure is decided by the communicator and we can't instantiate
	// that until we have a complete instance state. However, we *can* catch
	// configuration keys that are not valid for *any* communicator, catching
	// typos early rather than waiting until we actually try to run one of
	// the resource's provisioners.

	var diags tfdiags.Diagnostics

	// We evaluate here just by evaluating the block and returning any
	// diagnostics we get, since evaluation alone is enough to check for
	// extraneous arguments and incorrectly-typed arguments.
	_, _, configDiags := ctx.EvaluateBlock(config.Config, connectionBlockSupersetSchema, self, n.ResourceAddr.Key)
	diags = diags.Append(configDiags)

	return diags
}

// connectionBlockSupersetSchema is a schema representing the superset of all
// possible arguments for "connection" blocks across all supported connection
// types.
//
// This currently lives here because we've not yet updated our communicator
// subsystem to be aware of schema itself. Once that is done, we can remove
// this and use a type-specific schema from the communicator to validate
// exactly what is expected for a given connection type.
var connectionBlockSupersetSchema = &configschema.Block{
	Attributes: map[string]*configschema.Attribute{
		"type": {
			Type:     cty.String,
			Required: true,
		},

		// Common attributes for both connection types
		"user": {
			Type:     cty.String,
			Required: false,
		},
		"password": {
			Type:     cty.String,
			Required: false,
		},
		"host": {
			Type:     cty.String,
			Required: false,
		},
		"port": {
			Type:     cty.Number,
			Required: false,
		},
		"timeout": {
			Type:     cty.String,
			Required: false,
		},
		"script_path": {
			Type:     cty.String,
			Required: false,
		},

		// For type=ssh only (enforced in ssh communicator)
		"private_key": {
			Type:     cty.String,
			Required: false,
		},
		"host_key": {
			Type:     cty.String,
			Required: false,
		},
		"agent": {
			Type:     cty.Bool,
			Required: false,
		},
		"agent_identity": {
			Type:     cty.String,
			Required: false,
		},
		"bastion_host": {
			Type:     cty.String,
			Required: false,
		},
		"bastion_host_key": {
			Type:     cty.String,
			Required: false,
		},
		"bastion_port": {
			Type:     cty.Number,
			Required: false,
		},
		"bastion_user": {
			Type:     cty.String,
			Required: false,
		},
		"bastion_password": {
			Type:     cty.String,
			Required: false,
		},
		"bastion_private_key": {
			Type:     cty.String,
			Required: false,
		},

		// For type=winrm only (enforced in winrm communicator)
		"https": {
			Type:     cty.Bool,
			Required: false,
		},
		"insecure": {
			Type:     cty.Bool,
			Required: false,
		},
		"cacert": {
			Type:     cty.String,
			Required: false,
		},
		"use_ntlm": {
			Type:     cty.Bool,
			Required: false,
		},
	},
}

// EvalValidateResource is an EvalNode implementation that validates
// the configuration of a resource.
type EvalValidateResource struct {
	Addr           addrs.ResourceInstance
	Provider       *ResourceProvider
	ProviderSchema **ProviderSchema
	Config         *configs.Resource

	// IgnoreWarnings means that warnings will not be passed through. This allows
	// "just-in-time" passes of validation to continue execution through warnings.
	IgnoreWarnings bool

	// ConfigVal, if non-nil, will be updated with the value resulting from
	// evaluating the given configuration body. Since validation is performed
	// very early, this value is likely to contain lots of unknown values,
	// but its type will conform to the schema of the resource type associated
	// with the resource instance being validated.
	ConfigVal *cty.Value
}

func (n *EvalValidateResource) Eval(ctx EvalContext) (interface{}, error) {
	if n.ProviderSchema == nil {
		return nil, fmt.Errorf("EvalValidateResource has nil schema for %s", n.Addr)
	}

	var diags tfdiags.Diagnostics
	provider := *n.Provider
	cfg := *n.Config
	schema := *n.ProviderSchema
	mode := cfg.Mode

	var warns []string
	var errs []error

	// Provider entry point varies depending on resource mode, because
	// managed resources and data resources are two distinct concepts
	// in the provider abstraction.
	switch mode {
	case addrs.ManagedResourceMode:
		schema, exists := schema.ResourceTypes[cfg.Type]
		if !exists {
			diags = diags.Append(&hcl.Diagnostic{
				Severity: hcl.DiagError,
				Summary:  "Invalid resource type",
				Detail:   fmt.Sprintf("The provider %s does not support resource type %q.", cfg.ProviderConfigAddr(), cfg.Type),
				Subject:  &cfg.TypeRange,
			})
			return nil, diags.Err()
		}

		configVal, _, valDiags := ctx.EvaluateBlock(cfg.Config, schema, nil, n.Addr.Key)
		diags = diags.Append(valDiags)
		if valDiags.HasErrors() {
			return nil, diags.Err()
		}

		// The provider API still expects our legacy types, so we must do some
		// shimming here.
		legacyCfg := NewResourceConfigShimmed(configVal, schema)
		warns, errs = provider.ValidateResource(cfg.Type, legacyCfg)

		if n.ConfigVal != nil {
			*n.ConfigVal = configVal
		}

	case addrs.DataResourceMode:
		schema, exists := schema.DataSources[cfg.Type]
		if !exists {
			diags = diags.Append(&hcl.Diagnostic{
				Severity: hcl.DiagError,
				Summary:  "Invalid data source",
				Detail:   fmt.Sprintf("The provider %s does not support data source %q.", cfg.ProviderConfigAddr(), cfg.Type),
				Subject:  &cfg.TypeRange,
			})
			return nil, diags.Err()
		}

		configVal, _, valDiags := ctx.EvaluateBlock(cfg.Config, schema, nil, n.Addr.Key)
		diags = diags.Append(valDiags)
		if valDiags.HasErrors() {
			return nil, diags.Err()
		}

		// The provider API still expects our legacy types, so we must do some
		// shimming here.
		legacyCfg := NewResourceConfigShimmed(configVal, schema)
		warns, errs = provider.ValidateDataSource(cfg.Type, legacyCfg)

		if n.ConfigVal != nil {
			*n.ConfigVal = configVal
		}
	}

	// FIXME: Update the provider API to actually return diagnostics here,
	// and then we can remove all this shimming and use its diagnostics
	// directly.
	for _, warn := range warns {
		diags = diags.Append(tfdiags.SimpleWarning(warn))
	}
	for _, err := range errs {
		diags = diags.Append(err)
	}

	if n.IgnoreWarnings {
		// If we _only_ have warnings then we'll return nil.
		if diags.HasErrors() {
			return nil, diags.NonFatalErr()
		}
		return nil, nil
	} else {
		// We'll return an error if there are any diagnostics at all, even if
		// some of them are warnings.
		return nil, diags.NonFatalErr()
	}
}
<|endoftext|>