<commit_before>// Package pgx is a PostgreSQL database driver.
/*
pgx provides lower level access to PostgreSQL than the standard database/sql. It remains as similar to the database/sql
interface as possible while providing better speed and access to PostgreSQL specific features. Import
github.com/jackc/pgx/v4/stdlib to use pgx as a database/sql compatible driver.

Establishing a Connection

The primary way of establishing a connection is with `pgx.Connect`.

    conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))

The database connection string can be in URL or DSN format. Both PostgreSQL settings and pgx settings can be specified
here. In addition, a config struct can be created by `ParseConfig` and modified before establishing the connection with
`ConnectConfig` to configure settings such as tracing that cannot be configured with a connection string.

Connection Pool

`*pgx.Conn` represents a single connection to the database and is not concurrency safe. Use sub-package pgxpool for a
concurrency safe connection pool.

Query Interface

pgx implements Query and Scan in the familiar database/sql style.

    var sum int32

    // Send the query to the server. The returned rows MUST be closed
    // before conn can be used again.
    rows, err := conn.Query(context.Background(), "select generate_series(1,$1)", 10)
    if err != nil {
        return err
    }

    // rows.Close is called by rows.Next when all rows are read
    // or an error occurs in Next or Scan. So it may optionally be
    // omitted if nothing in the rows.Next loop can panic. It is
    // safe to close rows multiple times.
    defer rows.Close()

    // Iterate through the result set
    for rows.Next() {
        var n int32
        err = rows.Scan(&n)
        if err != nil {
            return err
        }
        sum += n
    }

    // Any errors encountered by rows.Next or rows.Scan will be returned here
    if rows.Err() != nil {
        return rows.Err()
    }

    // No errors found - do something with sum

ForEachRow can be used to execute a callback function for every row. This is often easier than iterating over rows
directly.

    var sum, n int32
    rows, _ := conn.Query(context.Background(), "select generate_series(1,$1)", 10)
    _, err := pgx.ForEachRow(rows, []any{&n}, func(pgx.QueryFuncRow) error {
      sum += n
      return nil
    })
    if err != nil {
      return err
    }

pgx also implements QueryRow in the same style as database/sql.

    var name string
    var weight int64
    err := conn.QueryRow(context.Background(), "select name, weight from widgets where id=$1", 42).Scan(&name, &weight)
    if err != nil {
        return err
    }

Use Exec to execute a query that does not return a result set.

    commandTag, err := conn.Exec(context.Background(), "delete from widgets where id=$1", 42)
    if err != nil {
        return err
    }
    if commandTag.RowsAffected() != 1 {
        return errors.New("No row found to delete")
    }

Base Type Mapping

pgx maps between all common base types directly between Go and PostgreSQL. In particular:

    Go           PostgreSQL
    -----------------------
    string       varchar
                 text

    // Integers are automatically be converted to any other integer type if
    // it can be done without overflow or underflow.
    int8
    int16        smallint
    int32        int
    int64        bigint
    int
    uint8
    uint16
    uint32
    uint64
    uint

    // Floats are strict and do not automatically convert like integers.
    float32      float4
    float64      float8

    time.Time   date
                timestamp
                timestamptz

    []byte      bytea

Null Mapping

pgx can map nulls in two ways. The first is package pgtype provides types that have a data field and a status field.
They work in a similar fashion to database/sql. The second is to use a pointer to a pointer.

    var foo pgtype.Varchar
    var bar *string
    err := conn.QueryRow("select foo, bar from widgets where id=$1", 42).Scan(&foo, &bar)
    if err != nil {
        return err
    }

Array Mapping

pgx maps between int16, int32, int64, float32, float64, and string Go slices and the equivalent PostgreSQL array type.
Go slices of native types do not support nulls, so if a PostgreSQL array that contains a null is read into a native Go
slice an error will occur. The pgtype package includes many more array types for PostgreSQL types that do not directly
map to native Go types.

JSON and JSONB Mapping

pgx includes built-in support to marshal and unmarshal between Go types and the PostgreSQL JSON and JSONB.

Inet and CIDR Mapping

pgx converts netip.Prefix and netip.Addr to and from inet and cidr PostgreSQL types.

Custom Type Support

pgx includes support for the common data types like integers, floats, strings, dates, and times that have direct
mappings between Go and SQL. In addition, pgx uses the github.com/jackc/pgtype library to support more types. See
documention for that library for instructions on how to implement custom types.

See example_custom_type_test.go for an example of a custom type for the PostgreSQL point type.

pgx also includes support for custom types implementing the database/sql.Scanner and database/sql/driver.Valuer
interfaces.

If pgx does cannot natively encode a type and that type is a renamed type (e.g. type MyTime time.Time) pgx will attempt
to encode the underlying type. While this is usually desired behavior it can produce surprising behavior if one the
underlying type and the renamed type each implement database/sql interfaces and the other implements pgx interfaces. It
is recommended that this situation be avoided by implementing pgx interfaces on the renamed type.

Composite types and row values

Row values and composite types are represented as pgtype.Record
(https://pkg.go.dev/github.com/jackc/pgtype?tab=doc#Record). It is possible to get values of your custom type by
implementing DecodeBinary interface. Decoding into pgtype.Record first can simplify process by avoiding dealing with raw
protocol directly.

For example:

    type MyType struct {
        a int      // NULL will cause decoding error
        b *string  // there can be NULL in this position in SQL
    }

    func (t *MyType) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error {
        r := pgtype.Record{
            Fields: []pgtype.Value{&pgtype.Int4{}, &pgtype.Text{}},
        }

        if err := r.DecodeBinary(ci, src); err != nil {
            return err
        }

        if r.Status != pgtype.Present {
            return errors.New("BUG: decoding should not be called on NULL value")
        }

        a := r.Fields[0].(*pgtype.Int4)
        b := r.Fields[1].(*pgtype.Text)

        // type compatibility is checked by AssignTo
        // only lossless assignments will succeed
        if err := a.AssignTo(&t.a); err != nil {
            return err
        }

        // AssignTo also deals with null value handling
        if err := b.AssignTo(&t.b); err != nil {
            return err
        }
        return nil
    }

    result := MyType{}
    err := conn.QueryRow(context.Background(), "select row(1, 'foo'::text)", pgx.QueryResultFormats{pgx.BinaryFormatCode}).Scan(&r)

Raw Bytes Mapping

[]byte passed as arguments to Query, QueryRow, and Exec are passed unmodified to PostgreSQL.

Transactions

Transactions are started by calling Begin.

    tx, err := conn.Begin(context.Background())
    if err != nil {
        return err
    }
    // Rollback is safe to call even if the tx is already closed, so if
    // the tx commits successfully, this is a no-op
    defer tx.Rollback(context.Background())

    _, err = tx.Exec(context.Background(), "insert into foo(id) values (1)")
    if err != nil {
        return err
    }

    err = tx.Commit(context.Background())
    if err != nil {
        return err
    }

The Tx returned from Begin also implements the Begin method. This can be used to implement pseudo nested transactions.
These are internally implemented with savepoints.

Use BeginTx to control the transaction mode.

BeginFunc and BeginTxFunc are functions that begin a transaction, execute a function, and commit or rollback the
transaction depending on the return value of the function. These can be simpler and less error prone to use.

    err = pgx.BeginFunc(context.Background(), conn, func(tx pgx.Tx) error {
        _, err := tx.Exec(context.Background(), "insert into foo(id) values (1)")
        return err
    })
    if err != nil {
        return err
    }

Prepared Statements

Prepared statements can be manually created with the Prepare method. However, this is rarely necessary because pgx
includes an automatic statement cache by default. Queries run through the normal Query, QueryRow, and Exec functions are
automatically prepared on first execution and the prepared statement is reused on subsequent executions. See ParseConfig
for information on how to customize or disable the statement cache.

Copy Protocol

Use CopyFrom to efficiently insert multiple rows at a time using the PostgreSQL copy protocol. CopyFrom accepts a
CopyFromSource interface. If the data is already in a [][]any use CopyFromRows to wrap it in a CopyFromSource interface.
Or implement CopyFromSource to avoid buffering the entire data set in memory.

    rows := [][]any{
        {"John", "Smith", int32(36)},
        {"Jane", "Doe", int32(29)},
    }

    copyCount, err := conn.CopyFrom(
        context.Background(),
        pgx.Identifier{"people"},
        []string{"first_name", "last_name", "age"},
        pgx.CopyFromRows(rows),
    )

When you already have a typed array using CopyFromSlice can be more convenient.

    rows := []User{
        {"John", "Smith", 36},
        {"Jane", "Doe", 29},
    }

    copyCount, err := conn.CopyFrom(
        context.Background(),
        pgx.Identifier{"people"},
        []string{"first_name", "last_name", "age"},
        pgx.CopyFromSlice(len(rows), func(i int) ([]any, error) {
            return []any{rows[i].FirstName, rows[i].LastName, rows[i].Age}, nil
        }),
    )

CopyFrom can be faster than an insert with as few as 5 rows.

Listen and Notify

pgx can listen to the PostgreSQL notification system with the `Conn.WaitForNotification` method. It blocks until a
notification is received or the context is canceled.

    _, err := conn.Exec(context.Background(), "listen channelname")
    if err != nil {
        return nil
    }

    if notification, err := conn.WaitForNotification(context.Background()); err != nil {
        // do something with notification
    }

Tracing and Logging

pgx supports tracing by setting ConnConfig.Tracer.

In addition, the tracelog package provides the TraceLog type which lets a traditional logger act as a Tracer.

Lower Level PostgreSQL Functionality

pgx is implemented on top of github.com/jackc/pgconn a lower level PostgreSQL driver. The Conn.PgConn() method can be
used to access this lower layer.

PgBouncer

pgx is compatible with PgBouncer in two modes. One is when the connection has a statement cache in "describe" mode. The
other is when the connection is using the simple protocol. This can be set with the PreferSimpleProtocol config option.
*/
package pgx
<commit_msg>Update PgBouncer docs<commit_after>// Package pgx is a PostgreSQL database driver.
/*
pgx provides lower level access to PostgreSQL than the standard database/sql. It remains as similar to the database/sql
interface as possible while providing better speed and access to PostgreSQL specific features. Import
github.com/jackc/pgx/v4/stdlib to use pgx as a database/sql compatible driver.

Establishing a Connection

The primary way of establishing a connection is with `pgx.Connect`.

    conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))

The database connection string can be in URL or DSN format. Both PostgreSQL settings and pgx settings can be specified
here. In addition, a config struct can be created by `ParseConfig` and modified before establishing the connection with
`ConnectConfig` to configure settings such as tracing that cannot be configured with a connection string.

Connection Pool

`*pgx.Conn` represents a single connection to the database and is not concurrency safe. Use sub-package pgxpool for a
concurrency safe connection pool.

Query Interface

pgx implements Query and Scan in the familiar database/sql style.

    var sum int32

    // Send the query to the server. The returned rows MUST be closed
    // before conn can be used again.
    rows, err := conn.Query(context.Background(), "select generate_series(1,$1)", 10)
    if err != nil {
        return err
    }

    // rows.Close is called by rows.Next when all rows are read
    // or an error occurs in Next or Scan. So it may optionally be
    // omitted if nothing in the rows.Next loop can panic. It is
    // safe to close rows multiple times.
    defer rows.Close()

    // Iterate through the result set
    for rows.Next() {
        var n int32
        err = rows.Scan(&n)
        if err != nil {
            return err
        }
        sum += n
    }

    // Any errors encountered by rows.Next or rows.Scan will be returned here
    if rows.Err() != nil {
        return rows.Err()
    }

    // No errors found - do something with sum

ForEachRow can be used to execute a callback function for every row. This is often easier than iterating over rows
directly.

    var sum, n int32
    rows, _ := conn.Query(context.Background(), "select generate_series(1,$1)", 10)
    _, err := pgx.ForEachRow(rows, []any{&n}, func(pgx.QueryFuncRow) error {
      sum += n
      return nil
    })
    if err != nil {
      return err
    }

pgx also implements QueryRow in the same style as database/sql.

    var name string
    var weight int64
    err := conn.QueryRow(context.Background(), "select name, weight from widgets where id=$1", 42).Scan(&name, &weight)
    if err != nil {
        return err
    }

Use Exec to execute a query that does not return a result set.

    commandTag, err := conn.Exec(context.Background(), "delete from widgets where id=$1", 42)
    if err != nil {
        return err
    }
    if commandTag.RowsAffected() != 1 {
        return errors.New("No row found to delete")
    }

Base Type Mapping

pgx maps between all common base types directly between Go and PostgreSQL. In particular:

    Go           PostgreSQL
    -----------------------
    string       varchar
                 text

    // Integers are automatically be converted to any other integer type if
    // it can be done without overflow or underflow.
    int8
    int16        smallint
    int32        int
    int64        bigint
    int
    uint8
    uint16
    uint32
    uint64
    uint

    // Floats are strict and do not automatically convert like integers.
    float32      float4
    float64      float8

    time.Time   date
                timestamp
                timestamptz

    []byte      bytea

Null Mapping

pgx can map nulls in two ways. The first is package pgtype provides types that have a data field and a status field.
They work in a similar fashion to database/sql. The second is to use a pointer to a pointer.

    var foo pgtype.Varchar
    var bar *string
    err := conn.QueryRow("select foo, bar from widgets where id=$1", 42).Scan(&foo, &bar)
    if err != nil {
        return err
    }

Array Mapping

pgx maps between int16, int32, int64, float32, float64, and string Go slices and the equivalent PostgreSQL array type.
Go slices of native types do not support nulls, so if a PostgreSQL array that contains a null is read into a native Go
slice an error will occur. The pgtype package includes many more array types for PostgreSQL types that do not directly
map to native Go types.

JSON and JSONB Mapping

pgx includes built-in support to marshal and unmarshal between Go types and the PostgreSQL JSON and JSONB.

Inet and CIDR Mapping

pgx converts netip.Prefix and netip.Addr to and from inet and cidr PostgreSQL types.

Custom Type Support

pgx includes support for the common data types like integers, floats, strings, dates, and times that have direct
mappings between Go and SQL. In addition, pgx uses the github.com/jackc/pgtype library to support more types. See
documention for that library for instructions on how to implement custom types.

See example_custom_type_test.go for an example of a custom type for the PostgreSQL point type.

pgx also includes support for custom types implementing the database/sql.Scanner and database/sql/driver.Valuer
interfaces.

If pgx does cannot natively encode a type and that type is a renamed type (e.g. type MyTime time.Time) pgx will attempt
to encode the underlying type. While this is usually desired behavior it can produce surprising behavior if one the
underlying type and the renamed type each implement database/sql interfaces and the other implements pgx interfaces. It
is recommended that this situation be avoided by implementing pgx interfaces on the renamed type.

Composite types and row values

Row values and composite types are represented as pgtype.Record
(https://pkg.go.dev/github.com/jackc/pgtype?tab=doc#Record). It is possible to get values of your custom type by
implementing DecodeBinary interface. Decoding into pgtype.Record first can simplify process by avoiding dealing with raw
protocol directly.

For example:

    type MyType struct {
        a int      // NULL will cause decoding error
        b *string  // there can be NULL in this position in SQL
    }

    func (t *MyType) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error {
        r := pgtype.Record{
            Fields: []pgtype.Value{&pgtype.Int4{}, &pgtype.Text{}},
        }

        if err := r.DecodeBinary(ci, src); err != nil {
            return err
        }

        if r.Status != pgtype.Present {
            return errors.New("BUG: decoding should not be called on NULL value")
        }

        a := r.Fields[0].(*pgtype.Int4)
        b := r.Fields[1].(*pgtype.Text)

        // type compatibility is checked by AssignTo
        // only lossless assignments will succeed
        if err := a.AssignTo(&t.a); err != nil {
            return err
        }

        // AssignTo also deals with null value handling
        if err := b.AssignTo(&t.b); err != nil {
            return err
        }
        return nil
    }

    result := MyType{}
    err := conn.QueryRow(context.Background(), "select row(1, 'foo'::text)", pgx.QueryResultFormats{pgx.BinaryFormatCode}).Scan(&r)

Raw Bytes Mapping

[]byte passed as arguments to Query, QueryRow, and Exec are passed unmodified to PostgreSQL.

Transactions

Transactions are started by calling Begin.

    tx, err := conn.Begin(context.Background())
    if err != nil {
        return err
    }
    // Rollback is safe to call even if the tx is already closed, so if
    // the tx commits successfully, this is a no-op
    defer tx.Rollback(context.Background())

    _, err = tx.Exec(context.Background(), "insert into foo(id) values (1)")
    if err != nil {
        return err
    }

    err = tx.Commit(context.Background())
    if err != nil {
        return err
    }

The Tx returned from Begin also implements the Begin method. This can be used to implement pseudo nested transactions.
These are internally implemented with savepoints.

Use BeginTx to control the transaction mode.

BeginFunc and BeginTxFunc are functions that begin a transaction, execute a function, and commit or rollback the
transaction depending on the return value of the function. These can be simpler and less error prone to use.

    err = pgx.BeginFunc(context.Background(), conn, func(tx pgx.Tx) error {
        _, err := tx.Exec(context.Background(), "insert into foo(id) values (1)")
        return err
    })
    if err != nil {
        return err
    }

Prepared Statements

Prepared statements can be manually created with the Prepare method. However, this is rarely necessary because pgx
includes an automatic statement cache by default. Queries run through the normal Query, QueryRow, and Exec functions are
automatically prepared on first execution and the prepared statement is reused on subsequent executions. See ParseConfig
for information on how to customize or disable the statement cache.

Copy Protocol

Use CopyFrom to efficiently insert multiple rows at a time using the PostgreSQL copy protocol. CopyFrom accepts a
CopyFromSource interface. If the data is already in a [][]any use CopyFromRows to wrap it in a CopyFromSource interface.
Or implement CopyFromSource to avoid buffering the entire data set in memory.

    rows := [][]any{
        {"John", "Smith", int32(36)},
        {"Jane", "Doe", int32(29)},
    }

    copyCount, err := conn.CopyFrom(
        context.Background(),
        pgx.Identifier{"people"},
        []string{"first_name", "last_name", "age"},
        pgx.CopyFromRows(rows),
    )

When you already have a typed array using CopyFromSlice can be more convenient.

    rows := []User{
        {"John", "Smith", 36},
        {"Jane", "Doe", 29},
    }

    copyCount, err := conn.CopyFrom(
        context.Background(),
        pgx.Identifier{"people"},
        []string{"first_name", "last_name", "age"},
        pgx.CopyFromSlice(len(rows), func(i int) ([]any, error) {
            return []any{rows[i].FirstName, rows[i].LastName, rows[i].Age}, nil
        }),
    )

CopyFrom can be faster than an insert with as few as 5 rows.

Listen and Notify

pgx can listen to the PostgreSQL notification system with the `Conn.WaitForNotification` method. It blocks until a
notification is received or the context is canceled.

    _, err := conn.Exec(context.Background(), "listen channelname")
    if err != nil {
        return nil
    }

    if notification, err := conn.WaitForNotification(context.Background()); err != nil {
        // do something with notification
    }

Tracing and Logging

pgx supports tracing by setting ConnConfig.Tracer.

In addition, the tracelog package provides the TraceLog type which lets a traditional logger act as a Tracer.

Lower Level PostgreSQL Functionality

pgx is implemented on top of github.com/jackc/pgconn a lower level PostgreSQL driver. The Conn.PgConn() method can be
used to access this lower layer.

PgBouncer

By default pgx automatically uses prepared statements. Prepared statements are incompaptible with PgBouncer. This can be
disabled by setting a different QueryExecMode in ConnConfig.DefaultQueryExecMode.
*/
package pgx
<|endoftext|>


<commit_before>/* Serving resource from zip file appended to Go executable (this enables on file deploy).

Making it happen:
	1. Add code to serve resources (see example below)
	2. Compile your executable
	3. Run the `nrsc` script from https://bitbucket.org/tebeka/nrsc/src
	4. Deploy

Example code:

	package main

	import (
		"fmt"
		"net/http"
		"os"

		"bitbucket.org/tebeka/nrsc"
	)

	type params struct {
		Number  int
	}

	func indexHandler(w http.ResponseWriter, req *http.Request) {
		t, err := nrsc.LoadTemplates(nil, "t.html")
		if err != nil {
			http.NotFound(w, req)
		}
		if err = t.Execute(w, params{7}); err != nil {
			http.NotFound(w, req)
		}
	}

	func main() {
		nrsc.Handle("/static/")
		nrsc.Mask(".tmpl$")
		http.HandleFunc("/", indexHandler)
		if err := http.ListenAndServe(":8080", nil); err != nil {
			fmt.Fprintf(os.Stderr, "error: %s\n", err)
			os.Exit(1)
		}
	}
*/
package nrsc
<commit_msg>updated doc<commit_after>/* Serving resource from zip file appended to Go executable (this enables on file deploy).

Making it happen:
	1. Add code to serve resources (see example below)
	2. Compile your executable
	3. Run "nrsc /path/to/exe /path/to/resources"
	4. Deploy

Example code:

	package main

	import (
		"fmt"
		"net/http"
		"os"

		"bitbucket.org/tebeka/nrsc"
	)

	type params struct {
		Number  int
	}

	func indexHandler(w http.ResponseWriter, req *http.Request) {
		t, err := nrsc.LoadTemplates(nil, "t.html")
		if err != nil {
			http.NotFound(w, req)
		}
		if err = t.Execute(w, params{7}); err != nil {
			http.NotFound(w, req)
		}
	}

	func main() {
		nrsc.Handle("/static/")
		nrsc.Mask(".tmpl$")
		http.HandleFunc("/", indexHandler)
		if err := http.ListenAndServe(":8080", nil); err != nil {
			fmt.Fprintf(os.Stderr, "error: %s\n", err)
			os.Exit(1)
		}
	}
*/
package nrsc
<|endoftext|>


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

// Doc is a simple document printer that produces the doc comments
// for its argument symbols, using a more Go-like UI than godoc.
// It can also search for symbols by looking in all packages, and
// case is ignored. For instance:
//	doc isupper
// will find unicode.IsUpper.
//
// usage:
//	doc pkg.name   # "doc io.Writer"
//	doc pkg name   # "doc fmt Printf"
//	doc name       # "doc isupper" (finds unicode.IsUpper)
//
package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/printer"
	"go/token"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"unicode"
	"unicode/utf8"
)

const usageDoc = `Find documentation for names.
usage:
	doc pkg.name   # "doc io.Writer"
	doc pkg name   # "doc fmt Printf"
	doc name       # "doc isupper" finds unicode.IsUpper
pkg is the last component of any package, e.g. fmt, parser
name is the name of an exported symbol; case is ignored in matches.
`

func usage() {
	fmt.Fprintf(os.Stderr, usageDoc)
	os.Exit(2)
}

func main() {
	flag.Parse()
	var pkg, name string
	switch flag.NArg() {
	case 1:
		if strings.Contains(flag.Arg(0), ".") {
			pkg, name = split(flag.Arg(0))
		} else {
			name = flag.Arg(0)
		}
	case 2:
		pkg, name = flag.Arg(0), flag.Arg(1)
	default:
		usage()
	}
	for _, path := range paths(pkg) {
		lookInDirectory(path, name)
	}
}

func split(arg string) (pkg, name string) {
	str := strings.Split(arg, ".")
	if len(str) != 2 {
		usage()
	}
	return str[0], str[1]
}

func paths(pkg string) []string {
	pkgs := pathsFor(runtime.GOROOT(), pkg)
	gopath := os.Getenv("GOPATH")
	if gopath != "" {
		for _, root := range splitGopath(gopath) {
			pkgs = append(pkgs, pathsFor(root, pkg)...)
		}
	}
	return pkgs
}

func splitGopath(gopath string) []string {
	// TODO: Assumes Unix.
	return strings.Split(gopath, ":")
}

// pathsFor recursively walks the tree looking for possible directories for the package:
// those whose basename is pkg.
func pathsFor(root, pkg string) []string {
	root = path.Join(root, "src")
	pkgPaths := make([]string, 0, 10)
	visit := func(pathName string, f os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		// One package per directory. Ignore the files themselves.
		if !f.IsDir() {
			return nil
		}
		// No .hg or other dot nonsense please.
		if strings.Contains(pathName, "/.") { // TODO: Unix-specific?
			return filepath.SkipDir
		}
		// Is the last element of the path correct
		if pkg == "" || path.Base(pathName) == pkg {
			pkgPaths = append(pkgPaths, pathName)
		}
		return nil
	}

	filepath.Walk(root, visit)
	return pkgPaths
}

// lookInDirectory looks in the package (if any) in the directory for the named exported identifier.
func lookInDirectory(directory, name string) {
	pkg, err := build.Default.ImportDir(directory, 0)
	if err != nil {
		// If it's just that there are no go source files, that's fine.
		if _, nogo := err.(*build.NoGoError); nogo {
			return
		}
		// Non-fatal: we are doing a recursive walk and there may be other directories.
		return
	}
	var fileNames []string
	fileNames = append(fileNames, pkg.GoFiles...)
	prefixDirectory(directory, fileNames)
	doPackage(fileNames, name)
}

// prefixDirectory places the directory name on the beginning of each name in the list.
func prefixDirectory(directory string, names []string) {
	if directory != "." {
		for i, name := range names {
			names[i] = filepath.Join(directory, name)
		}
	}
}

// File is a wrapper for the state of a file used in the parser.
// The parse tree walkers are all methods of this type.
type File struct {
	fset     *token.FileSet
	name     string
	ident    string
	file     *ast.File
	comments ast.CommentMap
}

// doPackage analyzes the single package constructed from the named files, looking for
// the definition of ident.
func doPackage(fileNames []string, ident string) {
	var files []*File
	var astFiles []*ast.File
	fs := token.NewFileSet()
	for _, name := range fileNames {
		f, err := os.Open(name)
		if err != nil {
			// Warn but continue to next package.
			fmt.Fprintf(os.Stderr, "%s: %s", name, err)
			return
		}
		defer f.Close()
		data, err := ioutil.ReadAll(f)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s: %s", name, err)
			return
		}
		parsedFile, err := parser.ParseFile(fs, name, bytes.NewReader(data), parser.ParseComments)
		if err != nil {
			// Noisy - just ignore.
			// fmt.Fprintf(os.Stderr, "%s: %s", name, err)
			return
		}
		thisFile := &File{
			fset:     fs,
			name:     name,
			ident:    ident,
			file:     parsedFile,
			comments: ast.NewCommentMap(fs, parsedFile, parsedFile.Comments),
		}
		files = append(files, thisFile)
		astFiles = append(astFiles, parsedFile)
	}
	for _, file := range files {
		ast.Walk(file, file.file)
	}
}

// Visit implements the ast.Visitor interface.
func (f *File) Visit(node ast.Node) ast.Visitor {
	switch n := node.(type) {
	case *ast.GenDecl:
		// Variables, constants, types.
		for _, spec := range n.Specs {
			switch spec := spec.(type) {
			case *ast.ValueSpec:
				for _, ident := range spec.Names {
					if equal(ident.Name, f.ident) {
						f.printNode(n, n.Doc)
						break
					}
				}
			case *ast.TypeSpec:
				if equal(spec.Name.Name, f.ident) {
					f.printNode(n, n.Doc)
				}
			case *ast.ImportSpec:
				continue // Don't care.
			}
		}
	case *ast.FuncDecl:
		// Methods, top-level functions.
		if equal(n.Name.Name, f.ident) {
			n.Body = nil // Do not print the function body.
			f.printNode(n, n.Doc)
		}
	}
	return f
}

func equal(n1, n2 string) bool {
	// n1 must  be exported.
	r, _ := utf8.DecodeRuneInString(n1)
	if !unicode.IsUpper(r) {
		return false
	}
	return strings.ToLower(n1) == strings.ToLower(n2)
}

func (f *File) printNode(node ast.Node, comments *ast.CommentGroup) {
	commentedNode := printer.CommentedNode{Node: node}
	if comments != nil {
		commentedNode.Comments = []*ast.CommentGroup{comments}
	}
	var b bytes.Buffer
	printer.Fprint(&b, f.fset, &commentedNode)
	posn := f.fset.Position(node.Pos())
	fmt.Printf("%s:%d:\n%s\n\n", posn.Filename, posn.Line, b.Bytes())
}
<commit_msg>doc: explain that pkg has no slashes.<commit_after>// Copyright 2013 The rspace Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Doc is a simple document printer that produces the doc comments
// for its argument symbols, using a more Go-like UI than godoc.
// It can also search for symbols by looking in all packages, and
// case is ignored. For instance:
//	doc isupper
// will find unicode.IsUpper.
//
// Usage:
//	doc pkg.name   # "doc io.Writer"
//	doc pkg name   # "doc fmt Printf"
//	doc name       # "doc isupper" (finds unicode.IsUpper)
//
// The pkg is the last name of the package; no slashes (ast.Node not go/ast.Node).
//
package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/printer"
	"go/token"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"unicode"
	"unicode/utf8"
)

const usageDoc = `Find documentation for names.
usage:
	doc pkg.name   # "doc io.Writer"
	doc pkg name   # "doc fmt Printf"
	doc name       # "doc isupper" finds unicode.IsUpper
pkg is the last component of any package, e.g. fmt, parser
name is the name of an exported symbol; case is ignored in matches.
`

func usage() {
	fmt.Fprintf(os.Stderr, usageDoc)
	os.Exit(2)
}

func main() {
	flag.Parse()
	var pkg, name string
	switch flag.NArg() {
	case 1:
		if strings.Contains(flag.Arg(0), ".") {
			pkg, name = split(flag.Arg(0))
		} else {
			name = flag.Arg(0)
		}
	case 2:
		pkg, name = flag.Arg(0), flag.Arg(1)
	default:
		usage()
	}
	for _, path := range paths(pkg) {
		lookInDirectory(path, name)
	}
}

func split(arg string) (pkg, name string) {
	str := strings.Split(arg, ".")
	if len(str) != 2 {
		usage()
	}
	return str[0], str[1]
}

func paths(pkg string) []string {
	pkgs := pathsFor(runtime.GOROOT(), pkg)
	gopath := os.Getenv("GOPATH")
	if gopath != "" {
		for _, root := range splitGopath(gopath) {
			pkgs = append(pkgs, pathsFor(root, pkg)...)
		}
	}
	return pkgs
}

func splitGopath(gopath string) []string {
	// TODO: Assumes Unix.
	return strings.Split(gopath, ":")
}

// pathsFor recursively walks the tree looking for possible directories for the package:
// those whose basename is pkg.
func pathsFor(root, pkg string) []string {
	root = path.Join(root, "src")
	pkgPaths := make([]string, 0, 10)
	visit := func(pathName string, f os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		// One package per directory. Ignore the files themselves.
		if !f.IsDir() {
			return nil
		}
		// No .hg or other dot nonsense please.
		if strings.Contains(pathName, "/.") { // TODO: Unix-specific?
			return filepath.SkipDir
		}
		// Is the last element of the path correct
		if pkg == "" || path.Base(pathName) == pkg {
			pkgPaths = append(pkgPaths, pathName)
		}
		return nil
	}

	filepath.Walk(root, visit)
	return pkgPaths
}

// lookInDirectory looks in the package (if any) in the directory for the named exported identifier.
func lookInDirectory(directory, name string) {
	pkg, err := build.Default.ImportDir(directory, 0)
	if err != nil {
		// If it's just that there are no go source files, that's fine.
		if _, nogo := err.(*build.NoGoError); nogo {
			return
		}
		// Non-fatal: we are doing a recursive walk and there may be other directories.
		return
	}
	var fileNames []string
	fileNames = append(fileNames, pkg.GoFiles...)
	prefixDirectory(directory, fileNames)
	doPackage(fileNames, name)
}

// prefixDirectory places the directory name on the beginning of each name in the list.
func prefixDirectory(directory string, names []string) {
	if directory != "." {
		for i, name := range names {
			names[i] = filepath.Join(directory, name)
		}
	}
}

// File is a wrapper for the state of a file used in the parser.
// The parse tree walkers are all methods of this type.
type File struct {
	fset     *token.FileSet
	name     string
	ident    string
	file     *ast.File
	comments ast.CommentMap
}

// doPackage analyzes the single package constructed from the named files, looking for
// the definition of ident.
func doPackage(fileNames []string, ident string) {
	var files []*File
	var astFiles []*ast.File
	fs := token.NewFileSet()
	for _, name := range fileNames {
		f, err := os.Open(name)
		if err != nil {
			// Warn but continue to next package.
			fmt.Fprintf(os.Stderr, "%s: %s", name, err)
			return
		}
		defer f.Close()
		data, err := ioutil.ReadAll(f)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s: %s", name, err)
			return
		}
		parsedFile, err := parser.ParseFile(fs, name, bytes.NewReader(data), parser.ParseComments)
		if err != nil {
			// Noisy - just ignore.
			// fmt.Fprintf(os.Stderr, "%s: %s", name, err)
			return
		}
		thisFile := &File{
			fset:     fs,
			name:     name,
			ident:    ident,
			file:     parsedFile,
			comments: ast.NewCommentMap(fs, parsedFile, parsedFile.Comments),
		}
		files = append(files, thisFile)
		astFiles = append(astFiles, parsedFile)
	}
	for _, file := range files {
		ast.Walk(file, file.file)
	}
}

// Visit implements the ast.Visitor interface.
func (f *File) Visit(node ast.Node) ast.Visitor {
	switch n := node.(type) {
	case *ast.GenDecl:
		// Variables, constants, types.
		for _, spec := range n.Specs {
			switch spec := spec.(type) {
			case *ast.ValueSpec:
				for _, ident := range spec.Names {
					if equal(ident.Name, f.ident) {
						f.printNode(n, n.Doc)
						break
					}
				}
			case *ast.TypeSpec:
				if equal(spec.Name.Name, f.ident) {
					f.printNode(n, n.Doc)
				}
			case *ast.ImportSpec:
				continue // Don't care.
			}
		}
	case *ast.FuncDecl:
		// Methods, top-level functions.
		if equal(n.Name.Name, f.ident) {
			n.Body = nil // Do not print the function body.
			f.printNode(n, n.Doc)
		}
	}
	return f
}

func equal(n1, n2 string) bool {
	// n1 must  be exported.
	r, _ := utf8.DecodeRuneInString(n1)
	if !unicode.IsUpper(r) {
		return false
	}
	return strings.ToLower(n1) == strings.ToLower(n2)
}

func (f *File) printNode(node ast.Node, comments *ast.CommentGroup) {
	commentedNode := printer.CommentedNode{Node: node}
	if comments != nil {
		commentedNode.Comments = []*ast.CommentGroup{comments}
	}
	var b bytes.Buffer
	printer.Fprint(&b, f.fset, &commentedNode)
	posn := f.fset.Position(node.Pos())
	fmt.Printf("%s:%d:\n%s\n\n", posn.Filename, posn.Line, b.Bytes())
}
<|endoftext|>


<commit_before>// Hanayo is the Ripple front-end web server.
package main

// version is the current version of hanayo
const version = "v1.8.1"
<commit_msg>⬆ v1.8.2 ⬆<commit_after>// Hanayo is the Ripple front-end web server.
package main

// version is the current version of hanayo
const version = "v1.8.2"
<|endoftext|>


<commit_before>/*
Package i18n is a helper for the Core (https://github.com/volatile/core).
It provides internationalization functions following the client preferences.

Installation

In the terminal:

	$ go get github.com/volatile/i18n

Usage

Example:

	package main

	import (
		"github.com/volatile/core"
		"github.com/volatile/i18n"
		"github.com/volatile/response"
		"golang.org/x/text/language"
	)

	func main() {
		i18n.Use(&locales, language.English, true) // Default locale is language.English and client locale will be saved in a cookie.
		response.ViewsFuncs(i18n.ViewsFuncs)       // Functions for views templates

		core.Use(func(c *core.Context) {
			response.View(c, "hello", map[string]interface{}{
				"name":        "John Doe",
				"coinsNumber": 500,
			})
		})

		core.Run()
	}

	var locales = i18n.Locales{
		language.English: {
			"decimalMark":   ".",
			"thousandsMark": ",",

			"hello":       "Hello %s,",
			"how":         "How are you?",
			"coinsZero":  "Your wallet is empty.",
			"coinsOne":   "You have a single and precious coin.",
			"coinsOther": "You have " + i18n.TransNPlaceholder + " coins.",
		},
		language.French: {
			"decimalMark":   ",",
			"thousandsMark": " ",

			"hello":       "Bonjour %s,",
			"how":         "Comment allez-vous?",
			"coinsZero":  "Vous êtes fauché.",
			"coinsOne":   "Vous avez une seule et précieuse pièce.",
			"coinsOther": "Vous possédez " + i18n.TransNPlaceholder + " pièces.",
		},
	}

In "views/hello.gohtml":

	{{define "hello"}}
		<!DOCTYPE html>

				<title>Hello</title>

				{{trans .c "hello" .name}}

				{{trans .c "how"}}

				{{transn .c "coins" .coinsNumber}}

	{{end}}

Locale detection

Only the standard Accept-Language header is used to detect the most appropriate locale for the client.

Get locale

Use ClientLocale to get the locale used for the client.

Set locale

If you don't want to use the Accept-Language header, you are free to use any client side strategy to get the a language tag:

- Form parameter — example: http://example.com/?locale=en
- Subdomain — example: http://en.example.com/
- URL path element — example: http://example.com/en/

After parsing a language tag, use SetClientLocale to manually set the locale used for the client.

Translations

Use Trans to get the translation for the client matched locale.
If the translation value contains format verbs (like %s or %d), the last variadic receives the content for them.

When the translation associated to key doesn't exist, an empty string is returned in production mode (otherwise, the key).

Pluralization

TransN works like Trans but it tries to find the best translation form, following a number of elements.

A pluralized translation has 3 forms: zero, one, other.
They are defined at the end of the key: "myTranslationKeyZero", "myTranslationKeyOne" and "myTranslationKeyOther".
If TransNPlaceholder is used in the translation, the number of elements will take this place.

Translation example:

	"appleZero" = "There are no apples."
	"appleOne" = "There is a single apple."
	"appleOther" = "There are " + i18n.TransNPlaceholder + " apples."

Function example:

	i18n.TransN(c, "apple", 7)

…results in "There are 7 apples".

Numbers

Use #Num to get a formatted number with decimal and thousands marks.
If set, the special "decimalMark" and "thousandsMark" keys will be used from the matched locale.

Views functions

ViewsFuncs provides a map of all functions usable in templates.

Example with the Response (https://github.com/volatile/response) package:

	response.ViewsFuncs(i18n.ViewsFuncs)
*/
package i18n
<commit_msg>Update doc<commit_after>/*
Package i18n is a helper for the Core (https://github.com/volatile/core).
It provides internationalization functions following the client preferences.

Installation

In the terminal:

	$ go get github.com/volatile/i18n

Usage

Example:

	package main

	import (
		"github.com/volatile/core"
		"github.com/volatile/i18n"
		"github.com/volatile/response"
		"golang.org/x/text/language"
	)

	func main() {
		i18n.Use(&locales, language.English, true) // Default locale is language.English and client locale will be saved in a cookie.
		response.ViewsFuncs(i18n.ViewsFuncs)       // Functions for views templates

		core.Use(func(c *core.Context) {
			response.View(c, "hello", map[string]interface{}{
				"name":        "John Doe",
				"coinsNumber": 500,
			})
		})

		core.Run()
	}

	var locales = i18n.Locales{
		language.English: {
			"decimalMark":   ".",
			"thousandsMark": ",",

			"hello":       "Hello %s,",
			"how":         "How are you?",
			"coinsZero":  "Your wallet is empty.",
			"coinsOne":   "You have a single and precious coin.",
			"coinsOther": "You have " + i18n.TransNPlaceholder + " coins.",
		},
		language.French: {
			"decimalMark":   ",",
			"thousandsMark": " ",

			"hello":       "Bonjour %s,",
			"how":         "Comment allez-vous?",
			"coinsZero":  "Vous êtes fauché.",
			"coinsOne":   "Vous avez une seule et précieuse pièce.",
			"coinsOther": "Vous possédez " + i18n.TransNPlaceholder + " pièces.",
		},
	}

In "views/hello.gohtml":

	{{define "hello"}}
		<!DOCTYPE html>

				<title>Hello</title>

				{{trans .c "hello" .name}}

				{{trans .c "how"}}

				{{transn .c "coins" .coinsNumber}}

	{{end}}

Locale detection

Only the standard Accept-Language header is used to detect the most appropriate locale for the client.

Get locale

Use ClientLocale to get the locale used for the client.

Set locale

If you don't want to use the Accept-Language header, you are free to use any client side strategy to get the a language tag:

● Form parameter — example: http://example.com/?locale=en

● Subdomain — example: http://en.example.com/

● URL path element — example: http://example.com/en/

After parsing a language tag, use SetClientLocale to manually set the locale used for the client.

Translations

Use Trans to get the translation for the client matched locale.
If the translation value contains format verbs (like %s or %d), the last variadic receives the content for them.

When the translation associated to key doesn't exist, an empty string is returned in production mode (otherwise, the key).

Pluralization

TransN works like Trans but it tries to find the best translation form, following a number of elements.

A pluralized translation has 3 forms: zero, one, other.
They are defined at the end of the key: "myTranslationKeyZero", "myTranslationKeyOne" and "myTranslationKeyOther".
If TransNPlaceholder is used in the translation, the number of elements will take this place.

Translation example:

	"appleZero" = "There are no apples."
	"appleOne" = "There is a single apple."
	"appleOther" = "There are " + i18n.TransNPlaceholder + " apples."

Function example:

	i18n.TransN(c, "apple", 7)

…results in "There are 7 apples".

Numbers

Use #Num to get a formatted number with decimal and thousands marks.
If set, the special "decimalMark" and "thousandsMark" keys will be used from the matched locale.

Views functions

ViewsFuncs provides a map of all functions usable in templates.

Example with the Response (https://github.com/volatile/response) package:

	response.ViewsFuncs(i18n.ViewsFuncs)
*/
package i18n
<|endoftext|>


<commit_before>// Copyright 2017 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 base

import (
	"fmt"
	"go/build"
	"os"
	"path/filepath"
	"runtime"

	"cmd/go/internal/cfg"
)

// Configuration for finding tool binaries.
var (
	ToolGOOS      = runtime.GOOS
	ToolGOARCH    = runtime.GOARCH
	ToolIsWindows = ToolGOOS == "windows"
	ToolDir       = build.ToolDir
)

const ToolWindowsExtension = ".exe"

// Tool returns the path to the named tool (for example, "vet").
// If the tool cannot be found, Tool exits the process.
func Tool(toolName string) string {
	toolPath := filepath.Join(ToolDir, toolName)
	if ToolIsWindows {
		toolPath += ToolWindowsExtension
	}
	if len(cfg.BuildToolexec) > 0 {
		return toolPath
	}
	// Give a nice message if there is no tool with that name.
	if _, err := os.Stat(toolPath); err != nil {
		if isInGoToolsRepo(toolName) {
			fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get golang.org/x/tools/cmd/%s\n", toolName, toolName)
		} else {
			fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
		}
		SetExitStatus(2)
		Exit()
	}
	return toolPath
}

// TODO: Delete.
func isInGoToolsRepo(toolName string) bool {
	return false
}
<commit_msg>cmd/go: delete unused function isInGoToolsRepo<commit_after>// Copyright 2017 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 base

import (
	"fmt"
	"go/build"
	"os"
	"path/filepath"
	"runtime"

	"cmd/go/internal/cfg"
)

// Configuration for finding tool binaries.
var (
	ToolGOOS      = runtime.GOOS
	ToolGOARCH    = runtime.GOARCH
	ToolIsWindows = ToolGOOS == "windows"
	ToolDir       = build.ToolDir
)

const ToolWindowsExtension = ".exe"

// Tool returns the path to the named tool (for example, "vet").
// If the tool cannot be found, Tool exits the process.
func Tool(toolName string) string {
	toolPath := filepath.Join(ToolDir, toolName)
	if ToolIsWindows {
		toolPath += ToolWindowsExtension
	}
	if len(cfg.BuildToolexec) > 0 {
		return toolPath
	}
	// Give a nice message if there is no tool with that name.
	if _, err := os.Stat(toolPath); err != nil {
		fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
		SetExitStatus(2)
		Exit()
	}
	return toolPath
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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 main

import (
	"fmt"
	"os/exec"
)

const (
	buildDefault = "quick"
)

type buildStrategy string

// Support both --build and --build=foo
func (b *buildStrategy) IsBoolFlag() bool {
	return true
}

// Return b as a string
func (b *buildStrategy) String() string {
	return string(*b)
}

// Set to --build=B or buildDefault if just --build
func (b *buildStrategy) Set(value string) error {
	if value == "true" { // just --build, choose default
		value = buildDefault
	}
	switch value {
	case "bazel", "quick", "release":
		*b = buildStrategy(value)
		return nil
	}
	return fmt.Errorf("Bad build strategy: %v (use: bash, quick, release)", value)
}

// True when this kubetest invocation wants to build a release
func (b *buildStrategy) Enabled() bool {
	return *b != ""
}

// Build kubernetes according to specified strategy.
// This may be a bazel, quick or full release build depending on --build=B.
func (b *buildStrategy) Build() error {
	var target string
	switch *b {
	case "bazel":
		target = "bazel-build"
	case "quick":
		target = "quick-release"
	case "release":
		target = "release"
	default:
		return fmt.Errorf("Unknown build strategy: %v", b)
	}

	// TODO(fejta): FIX ME
	// The build-release script needs stdin to ask the user whether
	// it's OK to download the docker image.
	return finishRunning(exec.Command("make", "-C", k8s("kubernetes"), target))
}
<commit_msg>Use `make bazel-release` instead of `make bazel-build` in kubetest<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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 main

import (
	"fmt"
	"os/exec"
)

const (
	buildDefault = "quick"
)

type buildStrategy string

// Support both --build and --build=foo
func (b *buildStrategy) IsBoolFlag() bool {
	return true
}

// Return b as a string
func (b *buildStrategy) String() string {
	return string(*b)
}

// Set to --build=B or buildDefault if just --build
func (b *buildStrategy) Set(value string) error {
	if value == "true" { // just --build, choose default
		value = buildDefault
	}
	switch value {
	case "bazel", "quick", "release":
		*b = buildStrategy(value)
		return nil
	}
	return fmt.Errorf("Bad build strategy: %v (use: bash, quick, release)", value)
}

// True when this kubetest invocation wants to build a release
func (b *buildStrategy) Enabled() bool {
	return *b != ""
}

// Build kubernetes according to specified strategy.
// This may be a bazel, quick or full release build depending on --build=B.
func (b *buildStrategy) Build() error {
	var target string
	switch *b {
	case "bazel":
		target = "bazel-release"
	case "quick":
		target = "quick-release"
	case "release":
		target = "release"
	default:
		return fmt.Errorf("Unknown build strategy: %v", b)
	}

	// TODO(fejta): FIX ME
	// The build-release script needs stdin to ask the user whether
	// it's OK to download the docker image.
	return finishRunning(exec.Command("make", "-C", k8s("kubernetes"), target))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"regexp"

	"github.com/cep21/xdgbasedir"
	"github.com/termie/go-shutil"
	"gopkg.in/yaml.v1"
)

func main() {
	lf := NewLocalFiles("")
	Main(os.Args, os.Stdout, os.Stderr, &lf)
}

// The programs usage help.
var Usage = `dwi.

Usage:
	dwi <file>
`

// FileIndex provides methods for manipulating a list of files.
type FileIndex interface {
	Exists(filename string) bool
	Open(filename string) (*os.File, error)
	IsDir(filename string) bool
	Rename(filename string, dest string) error
	Move(filename string, dest string) error
	Remove(filename string) error
}

// LocalFiles is a FileIndex for files in the local filesystem.
type LocalFiles struct {
	Root string
}

// Exists returns true if a file given by path exists.
func (lf *LocalFiles) Exists(filename string) bool {
	if _, err := os.Stat(lf.getFullPath(filename)); err != nil {
		return false
	}
	return true
}

// IsDir returns true if filename points to a directory.
func (lf *LocalFiles) IsDir(filename string) bool {
	fileInfo, err := os.Stat(lf.getFullPath(filename))
	if err != nil {
		return false
	}
	return fileInfo.IsDir()
}

// Open opens a file or returns an error.
func (lf *LocalFiles) Open(filename string) (*os.File, error) {
	return os.Open(lf.getFullPath(filename))
}

// Rename renames (moves) a file.
func (lf *LocalFiles) Rename(oldpath, newpath string) error {
	return os.Rename(lf.getFullPath(oldpath), lf.getFullPath(newpath))

}

// Move moves a directory or file to the destination directory.
func (lf *LocalFiles) Move(oldpath, newpath string) error {
	cmd := exec.Command("mv", "-v", lf.getFullPath(oldpath), lf.getFullPath(newpath))
	out, err := cmd.Output()
	fmt.Println(string(out))
	return err

	//err := lf.Rename(oldpath, newpath)

	//switch err.(type) {
	//case *os.LinkError:
	//err = lf.CopyWithTemp(oldpath, newpath)
	//}

	//return err
}

// Remove removes a file.
func (lf *LocalFiles) Remove(filename string) error {
	return os.Remove(lf.getFullPath(filename))
}

// CopyWithTemp copies a directory to the destination.
func (lf *LocalFiles) CopyWithTemp(oldpath, newpath string) error {
	// [TODO]: Actually do temp stuff - 2014-12-21 01:49pm
	src := lf.getFullPath(oldpath)
	dst := lf.getFullPath(newpath)
	//dstTemp := dst + ".diw-COPYING"
	//err := shutil.CopyTree(src, dstTemp, nil)
	err := shutil.CopyTree(src, dst, nil)
	if err != nil {
		return err
	}
	return err

	//return os.Rename(dstTemp, dst)
}

// GetFullPath returns the full path.
func (lf *LocalFiles) getFullPath(filename string) string {
	return path.Join(lf.Root, filename)
}

// NewLocalFiles creates and initializes a new LocalFiles with a given path root.
func NewLocalFiles(root string) LocalFiles {
	return LocalFiles{root}
}

// Main function.
func Main(args []string, out io.Writer, eout io.Writer, fi FileIndex) {
	if len(args) < 2 {
		fmt.Fprintln(out, Usage)
		return
	}

	files := ParseArgs(args)
	if AnyFilesDontExist(eout, fi, files) {
		return
	}

	configDir, err := xdgbasedir.ConfigHomeDirectory()
	if err != nil {
		return
	}

	rules := LoadRules(path.Join(configDir, "/dealwithit/rules.yaml"), fi, eout)

	ForEachMatchingFile(files, rules, out, eout, fi)
}

// AnyFilesDontExist will look for each of the given files in the given FileIndex,
// output an error to eout for any file that doesn't exist and return true if where any missing.
func AnyFilesDontExist(eout io.Writer, fi FileIndex, files []string) bool {
	err := false
	for _, f := range files {
		if !fi.Exists(f) {
			fmt.Fprintln(eout, "Error: File not found:", f)
			err = true
		}
	}
	return err
}

// ParseArgs takes a list of args and returns the list of files.
// The first arg must be the executable name.
func ParseArgs(args []string) []string {
	return args[1:]
}

type Rule map[string]string
type Rules []Rule

// LoadRules loads the rules file given by filename from the given FileIndex.
func LoadRules(filename string, fi FileIndex, eout io.Writer) Rules {
	var rules Rules

	file, err := fi.Open(filename)
	if err != nil {
		fmt.Fprintln(eout, "Error: Could not open rules file", filename, err)
		return rules
	}

	data, err := ioutil.ReadAll(file)
	if err != nil {
		fmt.Fprintln(eout, "Error: Could not read rules file", filename, err)
		return rules
	}

	rules = ParseRules(data, eout)
	return rules
}

// ParseRules parses the YAML.
func ParseRules(data []byte, eout io.Writer) Rules {
	var rules Rules
	err := yaml.Unmarshal(data, &rules)
	if err != nil {
		fmt.Fprintln(eout, "Error: Could not parse rules file", err)
		return rules
	}

	return rules
}

// ForEachMatchingFile executes a function on each file if the function match returns true.
func ForEachMatchingFile(files []string, rules Rules, out io.Writer, eout io.Writer, fi FileIndex) {
	for _, f := range files {
		matches, rule := FileMatchesRules(f, rules, eout, fi)

		if !matches {
			fmt.Fprintln(out, "No rule for", f)
			continue
		}

		ExecuteRule(f, rule, out, eout, fi)

	}
}

// FileMatchesRules if filename matches a rule given in rules returns true and the rule.
func FileMatchesRules(filename string, rules Rules, eout io.Writer, fi FileIndex) (bool, Rule) {
	for _, rule := range rules {
		if FileMatchesRule(filename, rule, eout) {
			return true, rule
		}
	}
	return false, nil
}

// FileMatchesRule return true if filename matches the rule given.
func FileMatchesRule(filename string, rule Rule, eout io.Writer) bool {
	if len(rule["file"]) == 0 {
		fmt.Fprintln(eout, "Error: Empty regexp.")
		return false
	}

	re, err := regexp.Compile(rule["file"])
	if err != nil {
		fmt.Fprintln(eout, "Error: Could not compile regexp", err)
		return false
	}

	return re.MatchString(filename)
}

// ExecuteRule executes the given rules on file.
func ExecuteRule(filename string, rule Rule, out io.Writer, eout io.Writer, fi FileIndex) {
	dest := rule["move"]

	if !fi.Exists(dest) || !fi.IsDir(dest) {
		fmt.Fprintf(eout, "Error: Invalid directory %s\n", dest)
		return
	}
	dest = path.Join(dest, path.Base(filename))

	if fi.Exists(dest) {
		fmt.Fprintln(eout, "Error: File already exists", dest)
		return
	}

	fmt.Fprintf(out, "mv -v \"%s\" \"%s\"\n", filename, dest)
	err := fi.Move(filename, dest)

	if err != nil {
		fmt.Fprint(eout, "Error:", err)
		return
	}

	//err = fi.Remove(filename)
	//if err != nil {
	//fmt.Fprint(eout, "Error:", err)
	//}
}
<commit_msg>Don't keep running if a mv command failed.<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"regexp"

	"github.com/cep21/xdgbasedir"
	"github.com/termie/go-shutil"
	"gopkg.in/yaml.v1"
)

func main() {
	lf := NewLocalFiles("")
	Main(os.Args, os.Stdout, os.Stderr, &lf)
}

// The programs usage help.
var Usage = `dwi.

Usage:
	dwi <file>
`

// FileIndex provides methods for manipulating a list of files.
type FileIndex interface {
	Exists(filename string) bool
	Open(filename string) (*os.File, error)
	IsDir(filename string) bool
	Rename(filename string, dest string) error
	Move(filename string, dest string) error
	Remove(filename string) error
}

// LocalFiles is a FileIndex for files in the local filesystem.
type LocalFiles struct {
	Root string
}

// Exists returns true if a file given by path exists.
func (lf *LocalFiles) Exists(filename string) bool {
	if _, err := os.Stat(lf.getFullPath(filename)); err != nil {
		return false
	}
	return true
}

// IsDir returns true if filename points to a directory.
func (lf *LocalFiles) IsDir(filename string) bool {
	fileInfo, err := os.Stat(lf.getFullPath(filename))
	if err != nil {
		return false
	}
	return fileInfo.IsDir()
}

// Open opens a file or returns an error.
func (lf *LocalFiles) Open(filename string) (*os.File, error) {
	return os.Open(lf.getFullPath(filename))
}

// Rename renames (moves) a file.
func (lf *LocalFiles) Rename(oldpath, newpath string) error {
	return os.Rename(lf.getFullPath(oldpath), lf.getFullPath(newpath))

}

// Move moves a directory or file to the destination directory.
func (lf *LocalFiles) Move(oldpath, newpath string) error {
	cmd := exec.Command("mv", "-v", lf.getFullPath(oldpath), lf.getFullPath(newpath))
	out, err := cmd.Output()
	fmt.Println(string(out))
	return err

	//err := lf.Rename(oldpath, newpath)

	//switch err.(type) {
	//case *os.LinkError:
	//err = lf.CopyWithTemp(oldpath, newpath)
	//}

	//return err
}

// Remove removes a file.
func (lf *LocalFiles) Remove(filename string) error {
	return os.Remove(lf.getFullPath(filename))
}

// CopyWithTemp copies a directory to the destination.
func (lf *LocalFiles) CopyWithTemp(oldpath, newpath string) error {
	// [TODO]: Actually do temp stuff - 2014-12-21 01:49pm
	src := lf.getFullPath(oldpath)
	dst := lf.getFullPath(newpath)
	//dstTemp := dst + ".diw-COPYING"
	//err := shutil.CopyTree(src, dstTemp, nil)
	err := shutil.CopyTree(src, dst, nil)
	if err != nil {
		return err
	}
	return err

	//return os.Rename(dstTemp, dst)
}

// GetFullPath returns the full path.
func (lf *LocalFiles) getFullPath(filename string) string {
	return path.Join(lf.Root, filename)
}

// NewLocalFiles creates and initializes a new LocalFiles with a given path root.
func NewLocalFiles(root string) LocalFiles {
	return LocalFiles{root}
}

// Main function.
func Main(args []string, out io.Writer, eout io.Writer, fi FileIndex) {
	if len(args) < 2 {
		fmt.Fprintln(out, Usage)
		return
	}

	files := ParseArgs(args)
	if AnyFilesDontExist(eout, fi, files) {
		return
	}

	configDir, err := xdgbasedir.ConfigHomeDirectory()
	if err != nil {
		return
	}

	rules := LoadRules(path.Join(configDir, "/dealwithit/rules.yaml"), fi, eout)

	ForEachMatchingFile(files, rules, out, eout, fi)
}

// AnyFilesDontExist will look for each of the given files in the given FileIndex,
// output an error to eout for any file that doesn't exist and return true if where any missing.
func AnyFilesDontExist(eout io.Writer, fi FileIndex, files []string) bool {
	err := false
	for _, f := range files {
		if !fi.Exists(f) {
			fmt.Fprintln(eout, "Error: File not found:", f)
			err = true
		}
	}
	return err
}

// ParseArgs takes a list of args and returns the list of files.
// The first arg must be the executable name.
func ParseArgs(args []string) []string {
	return args[1:]
}

type Rule map[string]string
type Rules []Rule

// LoadRules loads the rules file given by filename from the given FileIndex.
func LoadRules(filename string, fi FileIndex, eout io.Writer) Rules {
	var rules Rules

	file, err := fi.Open(filename)
	if err != nil {
		fmt.Fprintln(eout, "Error: Could not open rules file", filename, err)
		return rules
	}

	data, err := ioutil.ReadAll(file)
	if err != nil {
		fmt.Fprintln(eout, "Error: Could not read rules file", filename, err)
		return rules
	}

	rules = ParseRules(data, eout)
	return rules
}

// ParseRules parses the YAML.
func ParseRules(data []byte, eout io.Writer) Rules {
	var rules Rules
	err := yaml.Unmarshal(data, &rules)
	if err != nil {
		fmt.Fprintln(eout, "Error: Could not parse rules file", err)
		return rules
	}

	return rules
}

// ForEachMatchingFile executes a function on each file if the function match returns true.
func ForEachMatchingFile(files []string, rules Rules, out io.Writer, eout io.Writer, fi FileIndex) {
	for _, f := range files {
		matches, rule := FileMatchesRules(f, rules, eout, fi)

		if !matches {
			fmt.Fprintln(out, "No rule for", f)
			continue
		}

		err := ExecuteRule(f, rule, out, eout, fi)
		if err != nil {
			fmt.Fprintf(eout, "Aborting...")
			return
		}

	}
}

// FileMatchesRules if filename matches a rule given in rules returns true and the rule.
func FileMatchesRules(filename string, rules Rules, eout io.Writer, fi FileIndex) (bool, Rule) {
	for _, rule := range rules {
		if FileMatchesRule(filename, rule, eout) {
			return true, rule
		}
	}
	return false, nil
}

// FileMatchesRule return true if filename matches the rule given.
func FileMatchesRule(filename string, rule Rule, eout io.Writer) bool {
	if len(rule["file"]) == 0 {
		fmt.Fprintln(eout, "Error: Empty regexp.")
		return false
	}

	re, err := regexp.Compile(rule["file"])
	if err != nil {
		fmt.Fprintln(eout, "Error: Could not compile regexp", err)
		return false
	}

	return re.MatchString(filename)
}

// ExecuteRule executes the given rules on file.
func ExecuteRule(filename string, rule Rule, out io.Writer, eout io.Writer, fi FileIndex) error {
	dest := rule["move"]

	if !fi.Exists(dest) || !fi.IsDir(dest) {
		fmt.Fprintf(eout, "Error: Invalid directory %s\n", dest)
		return nil
	}
	dest = path.Join(dest, path.Base(filename))

	if fi.Exists(dest) {
		fmt.Fprintln(eout, "Error: File already exists", dest)
		return nil
	}

	fmt.Fprintf(out, "mv -v \"%s\" \"%s\"\n", filename, dest)
	err := fi.Move(filename, dest)

	if err != nil {
		fmt.Fprint(eout, "Error:", err)
		return err
	}

	//err = fi.Remove(filename)
	//if err != nil {
	//fmt.Fprint(eout, "Error:", err)
	//}
	return nil
}
<|endoftext|>


<commit_before>package ebpf

import (
	"bytes"
	"debug/elf"
	"encoding/binary"
	"io"
	"strings"

	"github.com/pkg/errors"
)

type elfCode struct {
	*elf.File
	symtab *symtab
}

// LoadCollectionSpecFromReader parses an io.ReaderAt that represents an ELF layout
// into a CollectionSpec.
func LoadCollectionSpecFromReader(code io.ReaderAt) (*CollectionSpec, error) {
	f, err := elf.NewFile(code)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	symbols, err := f.Symbols()
	if err != nil {
		return nil, errors.Wrap(err, "load symbols")
	}

	ec := &elfCode{f, newSymtab(symbols)}

	var licenseSection, versionSection *elf.Section
	progSections := make(map[int]*elf.Section)
	relSections := make(map[int]*elf.Section)
	mapSections := make(map[int]*elf.Section)
	for i, sec := range ec.Sections {
		switch {
		case strings.HasPrefix(sec.Name, "license"):
			licenseSection = sec
		case strings.HasPrefix(sec.Name, "version"):
			versionSection = sec
		case strings.HasPrefix(sec.Name, "maps"):
			mapSections[i] = sec
		case sec.Type == elf.SHT_REL:
			if int(sec.Info) >= len(ec.Sections) {
				return nil, errors.Errorf("found relocation section %v for missing section %v", i, sec.Info)
			}

			// Store relocations under the section index of the target
			idx := int(sec.Info)
			if relSections[idx] != nil {
				return nil, errors.Errorf("section %d has multiple relocation sections", idx)
			}
			relSections[idx] = sec
		case sec.Type == elf.SHT_PROGBITS && (sec.Flags&elf.SHF_EXECINSTR) != 0 && sec.Size > 0:
			progSections[i] = sec
		}
	}

	license, err := loadLicense(licenseSection)
	if err != nil {
		return nil, errors.Wrap(err, "load license")
	}

	version, err := loadVersion(versionSection, ec.ByteOrder)
	if err != nil {
		return nil, errors.Wrap(err, "load version")
	}

	maps, err := ec.loadMaps(mapSections)
	if err != nil {
		return nil, errors.Wrap(err, "load maps")
	}

	progs, libs, err := ec.loadPrograms(progSections, relSections, license, version)
	if err != nil {
		return nil, errors.Wrap(err, "load programs")
	}

	if len(libs) > 0 {
		for name, prog := range progs {
			editor := Edit(&prog.Instructions)
			if err := editor.Link(libs...); err != nil {
				return nil, errors.Wrapf(err, "program %s", name)
			}
		}
	}

	return &CollectionSpec{maps, progs}, nil
}

func loadLicense(sec *elf.Section) (string, error) {
	if sec == nil {
		return "", errors.Errorf("missing license section")
	}
	data, err := sec.Data()
	if err != nil {
		return "", errors.Wrapf(err, "section %s", sec.Name)
	}
	return string(bytes.TrimRight(data, "\000")), nil
}

func loadVersion(sec *elf.Section, bo binary.ByteOrder) (uint32, error) {
	if sec == nil {
		return 0, nil
	}
	data, err := sec.Data()
	if err != nil {
		return 0, errors.Wrapf(err, "section %s", sec.Name)
	}
	var version uint32
	return version, binary.Read(bytes.NewReader(data), bo, &version)
}

func (ec *elfCode) loadPrograms(progSections, relSections map[int]*elf.Section, license string, version uint32) (map[string]*ProgramSpec, []Instructions, error) {
	progs := make(map[string]*ProgramSpec)
	var libs []Instructions
	for idx, prog := range progSections {
		data, err := prog.Data()
		if err != nil {
			return nil, nil, err
		}

		funcSym := ec.symtab.forSectionOffset(idx, 0)
		if funcSym == nil {
			return nil, nil, errors.Errorf("section %v: no label at start", prog.Name)
		}

		insns, offsets, err := loadInstructions(ec.ByteOrder, data)
		if err != nil {
			return nil, nil, errors.Wrapf(err, "program %s", funcSym.Name)
		}

		err = assignSymbols(ec.symtab.forSection(idx), offsets, insns)
		if err != nil {
			return nil, nil, errors.Wrapf(err, "program %s", funcSym.Name)
		}

		if rels := relSections[idx]; rels != nil {
			err = ec.applyRelocations(insns, rels, offsets)
			if err != nil {
				return nil, nil, errors.Wrapf(err, "program %s", funcSym.Name)
			}
		}

		if progType := getProgType(prog.Name); progType == Unrecognized {
			// There is no single name we can use for "library" sections,
			// since they may contain multiple functions. We'll decode the
			// labels they contain later on, and then link sections that way.
			libs = append(libs, insns)
		} else {
			progs[funcSym.Name] = &ProgramSpec{
				Type:          progType,
				License:       license,
				KernelVersion: version,
				Instructions:  insns,
			}
		}
	}
	return progs, libs, nil
}

func (ec *elfCode) loadMaps(mapSections map[int]*elf.Section) (map[string]*MapSpec, error) {
	maps := make(map[string]*MapSpec)
	for idx, sec := range mapSections {
		// TODO: Iterate symbols
		n := len(ec.symtab.forSection(idx))
		if n == 0 {
			return nil, errors.Errorf("section %v: no symbols", sec.Name)
		}

		data, err := sec.Data()
		if err != nil {
			return nil, err
		}

		if len(data)%n != 0 {
			return nil, errors.Errorf("map descriptors are not of equal size")
		}

		size := len(data) / n
		var ordered []*MapSpec
		for i := 0; i < n; i++ {
			rd := bytes.NewReader(data[i*size : i*size+size])
			mapSym := ec.symtab.forSectionOffset(idx, uint64(i*size))
			if mapSym == nil {
				return nil, errors.Errorf("section %s: missing symbol for map #%d", sec.Name, i)
			}

			name := mapSym.Name
			if maps[name] != nil {
				return nil, errors.Errorf("section %v: map %v already exists", sec.Name, name)
			}

			var spec MapSpec
			var inner uint32
			switch {
			case binary.Read(rd, ec.ByteOrder, &spec.Type) != nil:
				return nil, errors.Errorf("map %v: missing type", name)
			case binary.Read(rd, ec.ByteOrder, &spec.KeySize) != nil:
				return nil, errors.Errorf("map %v: missing key size", name)
			case binary.Read(rd, ec.ByteOrder, &spec.ValueSize) != nil:
				return nil, errors.Errorf("map %v: missing value size", name)
			case binary.Read(rd, ec.ByteOrder, &spec.MaxEntries) != nil:
				return nil, errors.Errorf("map %v: missing max entries", name)
			case binary.Read(rd, ec.ByteOrder, &spec.Flags) != nil:
				return nil, errors.Errorf("map %v: missing flags", name)
			case rd.Len() > 0 && binary.Read(rd, ec.ByteOrder, &inner) != nil:
				return nil, errors.Errorf("map %v: can't read inner map index", name)
			}

			if rd.Len() != 0 {
				return nil, errors.Errorf("map %v: unknown fields in definition", name)
			}

			if spec.Type == ArrayOfMaps || spec.Type == HashOfMaps {
				if int(inner) > len(ordered) {
					return nil, errors.Errorf("map %v: invalid inner map index %d", name, inner)
				}

				innerSpec := ordered[int(inner)]
				if innerSpec.InnerMap != nil {
					return nil, errors.Errorf("map %v: can't nest map of map", name)
				}
				spec.InnerMap = innerSpec
			}

			maps[name] = &spec
			ordered = append(ordered, &spec)
		}
	}
	return maps, nil
}

func getProgType(v string) ProgType {
	types := map[string]ProgType{
		"socket":      SocketFilter,
		"seccomp":     SocketFilter,
		"kprobe/":     Kprobe,
		"kretprobe/":  Kprobe,
		"tracepoint/": TracePoint,
		"xdp":         XDP,
		"perf_event":  PerfEvent,
		"cgroup/skb":  CGroupSKB,
		"cgroup/sock": CGroupSock,
	}
	for k, t := range types {
		if strings.HasPrefix(v, k) {
			return t
		}
	}
	return Unrecognized
}

func loadInstructions(bo binary.ByteOrder, data []byte) (Instructions, map[uint64]int, error) {
	rd := bytes.NewReader(data)
	var insns Instructions
	// Since relocations point at an offset, we need to keep track which
	// offset maps to which instruction.
	offsets := make(map[uint64]int)
	for rd.Len() > 0 {
		offset := uint64(rd.Size()) - uint64(rd.Len())
		offsets[offset] = len(insns)

		var ins bpfInstruction
		if err := binary.Read(rd, bo, &ins); err != nil {
			return nil, nil, errors.Errorf("invalid instruction at offset %x", offset)
		}

		cons := int64(ins.Constant)
		if ins.OpCode == LdDW {
			var ins2 bpfInstruction
			if err := binary.Read(rd, bo, &ins2); err != nil {
				return nil, nil, errors.Errorf("invalid instruction at offset %x", offset)
			}
			if ins2.OpCode != 0 || ins2.Offset != 0 || ins2.Registers != 0 {
				return nil, nil, errors.Errorf("instruction at offset %x: 64bit immediate has non-zero fields", offset)
			}
			cons = int64(uint64(uint32(ins2.Constant))<<32 | uint64(uint32(ins.Constant)))
		}

		insns = append(insns, Instruction{
			OpCode:      ins.OpCode,
			DstRegister: ins.Registers.Dst(),
			SrcRegister: ins.Registers.Src(),
			Offset:      ins.Offset,
			Constant:    cons,
		})
	}
	return insns, offsets, nil
}

func assignSymbols(symbolOffsets map[uint64]*elf.Symbol, insOffsets map[uint64]int, insns Instructions) error {
	for offset, sym := range symbolOffsets {
		i, ok := insOffsets[offset]
		if !ok {
			return errors.Errorf("symbol %s: no instruction at offset %d", sym.Name, offset)
		}
		insns[i].Symbol = sym.Name
	}
	return nil
}

func (ec *elfCode) applyRelocations(insns Instructions, sec *elf.Section, offsets map[uint64]int) error {
	if sec.Entsize < 16 {
		return errors.Errorf("section %v: rls are less than 16 bytes", sec.Name)
	}

	data, err := sec.Data()
	if err != nil {
		return err
	}

	nRels := int(sec.Size / sec.Entsize)
	for i := 0; i < nRels; i++ {
		off := i * int(sec.Entsize)
		rd := bytes.NewReader(data[off : off+int(sec.Entsize)])

		var rel elf.Rel64
		if binary.Read(rd, ec.ByteOrder, &rel) != nil {
			return errors.Errorf("section %v: cannot parse relocation %v", sec.Name, i)
		}

		sym, err := ec.symtab.forRelocation(rel)
		if err != nil {
			return errors.Errorf("section %v: relocation %v: %v", sec.Name, i, err.Error())
		}

		idx, ok := offsets[rel.Off]
		if !ok {
			return errors.Errorf("section %v: symbol %v: invalid instruction offset %x", sec.Name, sym, rel.Off)
		}
		insns[idx].Reference = sym.Name
	}
	return nil
}

type symtab struct {
	Symbols []elf.Symbol
	index   map[int]map[uint64]*elf.Symbol
}

func newSymtab(symbols []elf.Symbol) *symtab {
	index := make(map[int]map[uint64]*elf.Symbol)
	for i, sym := range symbols {
		idx := int(sym.Section)
		if _, ok := index[idx]; !ok {
			index[idx] = make(map[uint64]*elf.Symbol)
		}
		index[idx][sym.Value] = &symbols[i]
	}
	return &symtab{
		symbols,
		index,
	}
}

func (st *symtab) forSection(sec int) map[uint64]*elf.Symbol {
	return st.index[sec]
}

func (st *symtab) forSectionOffset(sec int, offset uint64) *elf.Symbol {
	offsets := st.index[sec]
	if offsets == nil {
		return nil
	}
	return offsets[offset]
}

func (st *symtab) forRelocation(rel elf.Rel64) (*elf.Symbol, error) {
	symNo := int(rel.Info>>32) - 1
	if symNo >= len(st.Symbols) {
		return nil, errors.Errorf("symbol %v doesnt exist", symNo)
	}
	return &st.Symbols[symNo], nil
}
<commit_msg>add iproute2 program sections<commit_after>package ebpf

import (
	"bytes"
	"debug/elf"
	"encoding/binary"
	"io"
	"strings"

	"github.com/pkg/errors"
)

type elfCode struct {
	*elf.File
	symtab *symtab
}

// LoadCollectionSpecFromReader parses an io.ReaderAt that represents an ELF layout
// into a CollectionSpec.
func LoadCollectionSpecFromReader(code io.ReaderAt) (*CollectionSpec, error) {
	f, err := elf.NewFile(code)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	symbols, err := f.Symbols()
	if err != nil {
		return nil, errors.Wrap(err, "load symbols")
	}

	ec := &elfCode{f, newSymtab(symbols)}

	var licenseSection, versionSection *elf.Section
	progSections := make(map[int]*elf.Section)
	relSections := make(map[int]*elf.Section)
	mapSections := make(map[int]*elf.Section)
	for i, sec := range ec.Sections {
		switch {
		case strings.HasPrefix(sec.Name, "license"):
			licenseSection = sec
		case strings.HasPrefix(sec.Name, "version"):
			versionSection = sec
		case strings.HasPrefix(sec.Name, "maps"):
			mapSections[i] = sec
		case sec.Type == elf.SHT_REL:
			if int(sec.Info) >= len(ec.Sections) {
				return nil, errors.Errorf("found relocation section %v for missing section %v", i, sec.Info)
			}

			// Store relocations under the section index of the target
			idx := int(sec.Info)
			if relSections[idx] != nil {
				return nil, errors.Errorf("section %d has multiple relocation sections", idx)
			}
			relSections[idx] = sec
		case sec.Type == elf.SHT_PROGBITS && (sec.Flags&elf.SHF_EXECINSTR) != 0 && sec.Size > 0:
			progSections[i] = sec
		}
	}

	license, err := loadLicense(licenseSection)
	if err != nil {
		return nil, errors.Wrap(err, "load license")
	}

	version, err := loadVersion(versionSection, ec.ByteOrder)
	if err != nil {
		return nil, errors.Wrap(err, "load version")
	}

	maps, err := ec.loadMaps(mapSections)
	if err != nil {
		return nil, errors.Wrap(err, "load maps")
	}

	progs, libs, err := ec.loadPrograms(progSections, relSections, license, version)
	if err != nil {
		return nil, errors.Wrap(err, "load programs")
	}

	if len(libs) > 0 {
		for name, prog := range progs {
			editor := Edit(&prog.Instructions)
			if err := editor.Link(libs...); err != nil {
				return nil, errors.Wrapf(err, "program %s", name)
			}
		}
	}

	return &CollectionSpec{maps, progs}, nil
}

func loadLicense(sec *elf.Section) (string, error) {
	if sec == nil {
		return "", errors.Errorf("missing license section")
	}
	data, err := sec.Data()
	if err != nil {
		return "", errors.Wrapf(err, "section %s", sec.Name)
	}
	return string(bytes.TrimRight(data, "\000")), nil
}

func loadVersion(sec *elf.Section, bo binary.ByteOrder) (uint32, error) {
	if sec == nil {
		return 0, nil
	}
	data, err := sec.Data()
	if err != nil {
		return 0, errors.Wrapf(err, "section %s", sec.Name)
	}
	var version uint32
	return version, binary.Read(bytes.NewReader(data), bo, &version)
}

func (ec *elfCode) loadPrograms(progSections, relSections map[int]*elf.Section, license string, version uint32) (map[string]*ProgramSpec, []Instructions, error) {
	progs := make(map[string]*ProgramSpec)
	var libs []Instructions
	for idx, prog := range progSections {
		data, err := prog.Data()
		if err != nil {
			return nil, nil, err
		}

		funcSym := ec.symtab.forSectionOffset(idx, 0)
		if funcSym == nil {
			return nil, nil, errors.Errorf("section %v: no label at start", prog.Name)
		}

		insns, offsets, err := loadInstructions(ec.ByteOrder, data)
		if err != nil {
			return nil, nil, errors.Wrapf(err, "program %s", funcSym.Name)
		}

		err = assignSymbols(ec.symtab.forSection(idx), offsets, insns)
		if err != nil {
			return nil, nil, errors.Wrapf(err, "program %s", funcSym.Name)
		}

		if rels := relSections[idx]; rels != nil {
			err = ec.applyRelocations(insns, rels, offsets)
			if err != nil {
				return nil, nil, errors.Wrapf(err, "program %s", funcSym.Name)
			}
		}

		if progType := getProgType(prog.Name); progType == Unrecognized {
			// There is no single name we can use for "library" sections,
			// since they may contain multiple functions. We'll decode the
			// labels they contain later on, and then link sections that way.
			libs = append(libs, insns)
		} else {
			progs[funcSym.Name] = &ProgramSpec{
				Type:          progType,
				License:       license,
				KernelVersion: version,
				Instructions:  insns,
			}
		}
	}
	return progs, libs, nil
}

func (ec *elfCode) loadMaps(mapSections map[int]*elf.Section) (map[string]*MapSpec, error) {
	maps := make(map[string]*MapSpec)
	for idx, sec := range mapSections {
		// TODO: Iterate symbols
		n := len(ec.symtab.forSection(idx))
		if n == 0 {
			return nil, errors.Errorf("section %v: no symbols", sec.Name)
		}

		data, err := sec.Data()
		if err != nil {
			return nil, err
		}

		if len(data)%n != 0 {
			return nil, errors.Errorf("map descriptors are not of equal size")
		}

		size := len(data) / n
		var ordered []*MapSpec
		for i := 0; i < n; i++ {
			rd := bytes.NewReader(data[i*size : i*size+size])
			mapSym := ec.symtab.forSectionOffset(idx, uint64(i*size))
			if mapSym == nil {
				return nil, errors.Errorf("section %s: missing symbol for map #%d", sec.Name, i)
			}

			name := mapSym.Name
			if maps[name] != nil {
				return nil, errors.Errorf("section %v: map %v already exists", sec.Name, name)
			}

			var spec MapSpec
			var inner uint32
			switch {
			case binary.Read(rd, ec.ByteOrder, &spec.Type) != nil:
				return nil, errors.Errorf("map %v: missing type", name)
			case binary.Read(rd, ec.ByteOrder, &spec.KeySize) != nil:
				return nil, errors.Errorf("map %v: missing key size", name)
			case binary.Read(rd, ec.ByteOrder, &spec.ValueSize) != nil:
				return nil, errors.Errorf("map %v: missing value size", name)
			case binary.Read(rd, ec.ByteOrder, &spec.MaxEntries) != nil:
				return nil, errors.Errorf("map %v: missing max entries", name)
			case binary.Read(rd, ec.ByteOrder, &spec.Flags) != nil:
				return nil, errors.Errorf("map %v: missing flags", name)
			case rd.Len() > 0 && binary.Read(rd, ec.ByteOrder, &inner) != nil:
				return nil, errors.Errorf("map %v: can't read inner map index", name)
			}

			if rd.Len() != 0 {
				return nil, errors.Errorf("map %v: unknown fields in definition", name)
			}

			if spec.Type == ArrayOfMaps || spec.Type == HashOfMaps {
				if int(inner) > len(ordered) {
					return nil, errors.Errorf("map %v: invalid inner map index %d", name, inner)
				}

				innerSpec := ordered[int(inner)]
				if innerSpec.InnerMap != nil {
					return nil, errors.Errorf("map %v: can't nest map of map", name)
				}
				spec.InnerMap = innerSpec
			}

			maps[name] = &spec
			ordered = append(ordered, &spec)
		}
	}
	return maps, nil
}

func getProgType(v string) ProgType {
	types := map[string]ProgType{
		// From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/bpf/bpf_load.c?id=fb40c9ddd66b9c9bb811bbee125b3cb3ba1faee7#n60
		"socket":      SocketFilter,
		"seccomp":     SocketFilter,
		"kprobe/":     Kprobe,
		"kretprobe/":  Kprobe,
		"tracepoint/": TracePoint,
		"xdp":         XDP,
		"perf_event":  PerfEvent,
		"cgroup/skb":  CGroupSKB,
		"cgroup/sock": CGroupSock,
		// From https://github.com/CumulusNetworks/iproute2/blob/6335c5ff67202cf5b39eb929e2a0a5bb133627ba/include/bpf_elf.h#L19
		"classifier": SchedCLS,
		"action":     SchedACT,
	}
	for k, t := range types {
		if strings.HasPrefix(v, k) {
			return t
		}
	}
	return Unrecognized
}

func loadInstructions(bo binary.ByteOrder, data []byte) (Instructions, map[uint64]int, error) {
	rd := bytes.NewReader(data)
	var insns Instructions
	// Since relocations point at an offset, we need to keep track which
	// offset maps to which instruction.
	offsets := make(map[uint64]int)
	for rd.Len() > 0 {
		offset := uint64(rd.Size()) - uint64(rd.Len())
		offsets[offset] = len(insns)

		var ins bpfInstruction
		if err := binary.Read(rd, bo, &ins); err != nil {
			return nil, nil, errors.Errorf("invalid instruction at offset %x", offset)
		}

		cons := int64(ins.Constant)
		if ins.OpCode == LdDW {
			var ins2 bpfInstruction
			if err := binary.Read(rd, bo, &ins2); err != nil {
				return nil, nil, errors.Errorf("invalid instruction at offset %x", offset)
			}
			if ins2.OpCode != 0 || ins2.Offset != 0 || ins2.Registers != 0 {
				return nil, nil, errors.Errorf("instruction at offset %x: 64bit immediate has non-zero fields", offset)
			}
			cons = int64(uint64(uint32(ins2.Constant))<<32 | uint64(uint32(ins.Constant)))
		}

		insns = append(insns, Instruction{
			OpCode:      ins.OpCode,
			DstRegister: ins.Registers.Dst(),
			SrcRegister: ins.Registers.Src(),
			Offset:      ins.Offset,
			Constant:    cons,
		})
	}
	return insns, offsets, nil
}

func assignSymbols(symbolOffsets map[uint64]*elf.Symbol, insOffsets map[uint64]int, insns Instructions) error {
	for offset, sym := range symbolOffsets {
		i, ok := insOffsets[offset]
		if !ok {
			return errors.Errorf("symbol %s: no instruction at offset %d", sym.Name, offset)
		}
		insns[i].Symbol = sym.Name
	}
	return nil
}

func (ec *elfCode) applyRelocations(insns Instructions, sec *elf.Section, offsets map[uint64]int) error {
	if sec.Entsize < 16 {
		return errors.Errorf("section %v: rls are less than 16 bytes", sec.Name)
	}

	data, err := sec.Data()
	if err != nil {
		return err
	}

	nRels := int(sec.Size / sec.Entsize)
	for i := 0; i < nRels; i++ {
		off := i * int(sec.Entsize)
		rd := bytes.NewReader(data[off : off+int(sec.Entsize)])

		var rel elf.Rel64
		if binary.Read(rd, ec.ByteOrder, &rel) != nil {
			return errors.Errorf("section %v: cannot parse relocation %v", sec.Name, i)
		}

		sym, err := ec.symtab.forRelocation(rel)
		if err != nil {
			return errors.Errorf("section %v: relocation %v: %v", sec.Name, i, err.Error())
		}

		idx, ok := offsets[rel.Off]
		if !ok {
			return errors.Errorf("section %v: symbol %v: invalid instruction offset %x", sec.Name, sym, rel.Off)
		}
		insns[idx].Reference = sym.Name
	}
	return nil
}

type symtab struct {
	Symbols []elf.Symbol
	index   map[int]map[uint64]*elf.Symbol
}

func newSymtab(symbols []elf.Symbol) *symtab {
	index := make(map[int]map[uint64]*elf.Symbol)
	for i, sym := range symbols {
		idx := int(sym.Section)
		if _, ok := index[idx]; !ok {
			index[idx] = make(map[uint64]*elf.Symbol)
		}
		index[idx][sym.Value] = &symbols[i]
	}
	return &symtab{
		symbols,
		index,
	}
}

func (st *symtab) forSection(sec int) map[uint64]*elf.Symbol {
	return st.index[sec]
}

func (st *symtab) forSectionOffset(sec int, offset uint64) *elf.Symbol {
	offsets := st.index[sec]
	if offsets == nil {
		return nil
	}
	return offsets[offset]
}

func (st *symtab) forRelocation(rel elf.Rel64) (*elf.Symbol, error) {
	symNo := int(rel.Info>>32) - 1
	if symNo >= len(st.Symbols) {
		return nil, errors.Errorf("symbol %v doesnt exist", symNo)
	}
	return &st.Symbols[symNo], nil
}
<|endoftext|>


<commit_before>package infinispan

import (
	"fmt"
	"testing"
)

func TestEncodeInt(t *testing.T) {

	p := NewBuffer(nil)
	fmt.Printf("Original buffer: %v\n", p.buf)
	p.EncodeVarint(0)
	p.EncodeVarint(1)
	p.EncodeVarint(2)
	fmt.Printf("Original buffer: %v\n", p.buf)
	if p.buf[0] != byte(0) {
		t.Errorf("Wrong encoded value, expected %d, was %d", 0, p.buf[0])
	}
	if p.buf[1] != byte(1) {
		t.Errorf("Wrong encoded value, expected %d, was %d", 1, p.buf[1])
	}
	if p.buf[2] != byte(2) {
		t.Errorf("Wrong encoded value, expected %d, was %d", 2, p.buf[2])
	}

}

func TestEncodeString(t *testing.T) {

	original := "infinispan"
	plus := "rocks"

	p := NewBuffer(nil)
	fmt.Printf("Original buffer: %v\n", p.buf)
	p.EncodeString(original)
	fmt.Printf("First string: %v\n", p.buf)
	p.EncodeString(plus)

	if p.buf[0] != byte(len(original)) {
		expectedLen := int(p.buf[0])
		t.Errorf("Wrong length, expected %d, was %d", len(original), expectedLen)
	}

	encoded := string(p.buf[1 : len(original)+1])
	if encoded != original {
		t.Errorf("Wrong string, expected %s, was %s", original, encoded)
	}

	if p.buf[len(original)+1] != byte(len(plus)) {
		expectedLen := int(p.buf[len(original)+1])
		t.Errorf("Wrong length, expected %d, was %d", len(original)+1, expectedLen)
	}

	encoded = string(p.buf[len(original)+2:])
	if encoded != plus {
		t.Errorf("Wrong string, expected %s, was %s", plus, encoded)
	}

	fmt.Printf("Second string: %v\n", p.buf)

}

func TestEncodeEmptyString(t *testing.T) {

	p := NewBuffer(nil)
	original := ""
	p.EncodeString(original)

	if len(p.buf) != 1 {
		t.Errorf("Wrong length of empty string, expected %d, was %d", 1, len(p.buf))
	}

	if p.buf[0] != 0 {
		t.Errorf("Wrong empty string, byte value expected is %d, was %d", 0, int(p.buf[0]))
	}

}

func TestDecodeString(t *testing.T) {

	buf := []byte{
		0x04, //Value length
		0x75, //u
		0x67, //g
		0x6F, //o
		0x6c, //l
	}

	ugol := DecodeString(buf)

	if ugol != "ugol" {
		t.Errorf("Wrong string, expected %s, was %s", "ugol", ugol)
	}

}

func TestDecodeEmptyString(t *testing.T) {

	buf := []byte{
		0x00, //Value length
	}

	empty := DecodeString(buf)

	if empty != "" {
		t.Errorf("Wrong string, expected %s, was %s", "", empty)
	}

}
<commit_msg>Deleted fmt.printf<commit_after>package infinispan

import "testing"

func TestEncodeInt(t *testing.T) {

	p := NewBuffer(nil)
	p.EncodeVarint(0)
	p.EncodeVarint(1)
	p.EncodeVarint(2)
	if p.buf[0] != byte(0) {
		t.Errorf("Wrong encoded value, expected %d, was %d", 0, p.buf[0])
	}
	if p.buf[1] != byte(1) {
		t.Errorf("Wrong encoded value, expected %d, was %d", 1, p.buf[1])
	}
	if p.buf[2] != byte(2) {
		t.Errorf("Wrong encoded value, expected %d, was %d", 2, p.buf[2])
	}

}

func TestEncodeString(t *testing.T) {

	original := "infinispan"
	plus := "rocks"

	p := NewBuffer(nil)
	p.EncodeString(original)
	p.EncodeString(plus)

	if p.buf[0] != byte(len(original)) {
		expectedLen := int(p.buf[0])
		t.Errorf("Wrong length, expected %d, was %d", len(original), expectedLen)
	}

	encoded := string(p.buf[1 : len(original)+1])
	if encoded != original {
		t.Errorf("Wrong string, expected %s, was %s", original, encoded)
	}

	if p.buf[len(original)+1] != byte(len(plus)) {
		expectedLen := int(p.buf[len(original)+1])
		t.Errorf("Wrong length, expected %d, was %d", len(original)+1, expectedLen)
	}

	encoded = string(p.buf[len(original)+2:])
	if encoded != plus {
		t.Errorf("Wrong string, expected %s, was %s", plus, encoded)
	}

}

func TestEncodeEmptyString(t *testing.T) {

	p := NewBuffer(nil)
	original := ""
	p.EncodeString(original)

	if len(p.buf) != 1 {
		t.Errorf("Wrong length of empty string, expected %d, was %d", 1, len(p.buf))
	}

	if p.buf[0] != 0 {
		t.Errorf("Wrong empty string, byte value expected is %d, was %d", 0, int(p.buf[0]))
	}

}

func TestDecodeString(t *testing.T) {

	buf := []byte{
		0x04, //Value length
		0x75, //u
		0x67, //g
		0x6F, //o
		0x6c, //l
	}

	ugol := DecodeString(buf)

	if ugol != "ugol" {
		t.Errorf("Wrong string, expected %s, was %s", "ugol", ugol)
	}

}

func TestDecodeEmptyString(t *testing.T) {

	buf := []byte{
		0x00, //Value length
	}

	empty := DecodeString(buf)

	if empty != "" {
		t.Errorf("Wrong string, expected %s, was %s", "", empty)
	}

}
<|endoftext|>


<commit_before>// EME (ECB-Mix-ECB) is a wide-block encryption mode presented in the 2003 paper
// "A Parallelizable Enciphering Mode" by Halevi and Rogaway.
// This is an implementation of EME in Go.
package eme

import (
	"crypto/cipher"
	"log"
)

type directionConst bool

const (
	DirectionEncrypt = directionConst(true)
	DirectionDecrypt = directionConst(false)
)

// multByTwo - GF multiplication as specified in the EME-32 draft
func multByTwo(out []byte, in []byte) {
	if len(in) != 16 {
		panic("len must be 16")
	}
	tmp := make([]byte, 16)

	tmp[0] = 2 * in[0]
	if in[15] >= 128 {
		tmp[0] = tmp[0] ^ 135
	}
	for j := 1; j < 16; j++ {
		tmp[j] = 2 * in[j]
		if in[j-1] >= 128 {
			tmp[j] += 1
		}
	}
	copy(out, tmp)
}

func xorBlocks(out []byte, in1 []byte, in2 []byte) {
	if len(in1) != len(in2) {
		log.Panicf("len(in1)=%d is not equal to len(in2)=%d", len(in1), len(in2))
	}

	for i := range in1 {
		out[i] = in1[i] ^ in2[i]
	}
}

// aesTransform - encrypt or decrypt (according to "direction") using block
// cipher "bc" (typically AES)
func aesTransform(dst []byte, src []byte, direction directionConst, bc cipher.Block) {
	if direction == DirectionEncrypt {
		bc.Encrypt(dst, src)
		return
	} else if direction == DirectionDecrypt {
		bc.Decrypt(dst, src)
		return
	}
}

// tabulateL - calculate L_i for messages up to a length of m cipher blocks
func tabulateL(bc cipher.Block, m int) [][]byte {
	/* set L0 = 2*AESenc(K; 0) */
	eZero := make([]byte, 16)
	Li := make([]byte, 16)
	bc.Encrypt(Li, eZero)

	LTable := make([][]byte, m)
	// Allocate pool once and slice into m pieces in the loop
	pool := make([]byte, m*16)
	for i := 0; i < m; i++ {
		multByTwo(Li, Li)
		LTable[i] = pool[i*16 : (i+1)*16]
		copy(LTable[i], Li)
	}
	return LTable
}

// Transform - EME-encrypt or EME-decrypt, according to "direction"
// (defined in the constants DirectionEncrypt and DirectionDecrypt).
// The data in "P" is en- or decrypted with the block ciper "bc" under tweak "T".
// The result is returned in a freshly allocated slice.
func Transform(bc cipher.Block, T []byte, P []byte, direction directionConst) (C []byte) {
	if bc.BlockSize() != 16 {
		log.Panicf("Using a block size other than 16 is not implemented")
	}
	if len(T) != 16 {
		log.Panicf("Tweak must be 16 bytes long, is %d", len(T))
	}
	if len(P)%16 != 0 {
		log.Panicf("Data P must be a multiple of 16 long, is %d", len(P))
	}
	m := len(P) / 16
	if m == 0 || m > 16*8 {
		log.Panicf("EME operates on 1 to %d block-cipher blocks, you passed %d", 16*8, m)
	}

	C = make([]byte, len(P))

	LTable := tabulateL(bc, m)

	PPj := make([]byte, 16)
	for j := 0; j < m; j++ {
		Pj := P[j*16 : (j+1)*16]
		/* PPj = 2**(j-1)*L xor Pj */
		xorBlocks(PPj, Pj, LTable[j])
		/* PPPj = AESenc(K; PPj) */
		aesTransform(C[j*16:(j+1)*16], PPj, direction, bc)
	}

	/* MP =(xorSum PPPj) xor T */
	MP := make([]byte, 16)
	xorBlocks(MP, C[0:16], T)
	for j := 1; j < m; j++ {
		xorBlocks(MP, MP, C[j*16:(j+1)*16])
	}

	/* MC = AESenc(K; MP) */
	MC := make([]byte, 16)
	aesTransform(MC, MP, direction, bc)

	/* M = MP xor MC */
	M := make([]byte, 16)
	xorBlocks(M, MP, MC)
	CCCj := make([]byte, 16)
	for j := 1; j < m; j++ {
		multByTwo(M, M)
		/* CCCj = 2**(j-1)*M xor PPPj */
		xorBlocks(CCCj, C[j*16:(j+1)*16], M)
		copy(C[j*16:(j+1)*16], CCCj)
	}

	/* CCC1 = (xorSum CCCj) xor T xor MC */
	CCC1 := make([]byte, 16)
	xorBlocks(CCC1, MC, T)
	for j := 1; j < m; j++ {
		xorBlocks(CCC1, CCC1, C[j*16:(j+1)*16])
	}
	copy(C[0:16], CCC1)

	for j := 0; j < m; j++ {
		/* CCj = AES-enc(K; CCCj) */
		aesTransform(C[j*16:(j+1)*16], C[j*16:(j+1)*16], direction, bc)
		/* Cj = 2**(j-1)*L xor CCj */
		xorBlocks(C[j*16:(j+1)*16], C[j*16:(j+1)*16], LTable[j])
	}

	return C
}
<commit_msg>Rename arguments to human-readable<commit_after>// EME (ECB-Mix-ECB) is a length-preserving wide-block encryption mode. It was
// presented in the 2003 paper "A Parallelizable Enciphering Mode" by Halevi
// and Rogaway.
package eme

import (
	"crypto/cipher"
	"log"
)

type directionConst bool

const (
	// Encrypt "inputData"
	DirectionEncrypt = directionConst(true)
	// Decrypt "inputData"
	DirectionDecrypt = directionConst(false)
)

// multByTwo - GF multiplication as specified in the EME-32 draft
func multByTwo(out []byte, in []byte) {
	if len(in) != 16 {
		panic("len must be 16")
	}
	tmp := make([]byte, 16)

	tmp[0] = 2 * in[0]
	if in[15] >= 128 {
		tmp[0] = tmp[0] ^ 135
	}
	for j := 1; j < 16; j++ {
		tmp[j] = 2 * in[j]
		if in[j-1] >= 128 {
			tmp[j] += 1
		}
	}
	copy(out, tmp)
}

func xorBlocks(out []byte, in1 []byte, in2 []byte) {
	if len(in1) != len(in2) {
		log.Panicf("len(in1)=%d is not equal to len(in2)=%d", len(in1), len(in2))
	}

	for i := range in1 {
		out[i] = in1[i] ^ in2[i]
	}
}

// aesTransform - encrypt or decrypt (according to "direction") using block
// cipher "bc" (typically AES)
func aesTransform(dst []byte, src []byte, direction directionConst, bc cipher.Block) {
	if direction == DirectionEncrypt {
		bc.Encrypt(dst, src)
		return
	} else if direction == DirectionDecrypt {
		bc.Decrypt(dst, src)
		return
	}
}

// tabulateL - calculate L_i for messages up to a length of m cipher blocks
func tabulateL(bc cipher.Block, m int) [][]byte {
	/* set L0 = 2*AESenc(K; 0) */
	eZero := make([]byte, 16)
	Li := make([]byte, 16)
	bc.Encrypt(Li, eZero)

	LTable := make([][]byte, m)
	// Allocate pool once and slice into m pieces in the loop
	pool := make([]byte, m*16)
	for i := 0; i < m; i++ {
		multByTwo(Li, Li)
		LTable[i] = pool[i*16 : (i+1)*16]
		copy(LTable[i], Li)
	}
	return LTable
}

// Transform - EME-encrypt or EME-decrypt, according to "direction"
// (defined in the constants DirectionEncrypt and DirectionDecrypt).
// The data in "inputData" is en- or decrypted with the block ciper "bc" under
// "tweak" (also known as IV).
// The result is returned in a freshly allocated slice.
func Transform(bc cipher.Block, tweak []byte, inputData []byte, direction directionConst) []byte {
	// In the paper, the tweak is just called "T". Call it the same here to
	// make following the paper easy.
	T := tweak
	// In the paper, the plaintext data is called "P" and the ciphertext is
	// called "C". Because encryption and decryption are virtually indentical,
	// we share the code and always call the input data "P" and the output data
	// "C", regardless of the direction.
	P := inputData

	if bc.BlockSize() != 16 {
		log.Panicf("Using a block size other than 16 is not implemented")
	}
	if len(T) != 16 {
		log.Panicf("Tweak must be 16 bytes long, is %d", len(T))
	}
	if len(P)%16 != 0 {
		log.Panicf("Data P must be a multiple of 16 long, is %d", len(P))
	}
	m := len(P) / 16
	if m == 0 || m > 16*8 {
		log.Panicf("EME operates on 1 to %d block-cipher blocks, you passed %d", 16*8, m)
	}

	C := make([]byte, len(P))

	LTable := tabulateL(bc, m)

	PPj := make([]byte, 16)
	for j := 0; j < m; j++ {
		Pj := P[j*16 : (j+1)*16]
		/* PPj = 2**(j-1)*L xor Pj */
		xorBlocks(PPj, Pj, LTable[j])
		/* PPPj = AESenc(K; PPj) */
		aesTransform(C[j*16:(j+1)*16], PPj, direction, bc)
	}

	/* MP =(xorSum PPPj) xor T */
	MP := make([]byte, 16)
	xorBlocks(MP, C[0:16], T)
	for j := 1; j < m; j++ {
		xorBlocks(MP, MP, C[j*16:(j+1)*16])
	}

	/* MC = AESenc(K; MP) */
	MC := make([]byte, 16)
	aesTransform(MC, MP, direction, bc)

	/* M = MP xor MC */
	M := make([]byte, 16)
	xorBlocks(M, MP, MC)
	CCCj := make([]byte, 16)
	for j := 1; j < m; j++ {
		multByTwo(M, M)
		/* CCCj = 2**(j-1)*M xor PPPj */
		xorBlocks(CCCj, C[j*16:(j+1)*16], M)
		copy(C[j*16:(j+1)*16], CCCj)
	}

	/* CCC1 = (xorSum CCCj) xor T xor MC */
	CCC1 := make([]byte, 16)
	xorBlocks(CCC1, MC, T)
	for j := 1; j < m; j++ {
		xorBlocks(CCC1, CCC1, C[j*16:(j+1)*16])
	}
	copy(C[0:16], CCC1)

	for j := 0; j < m; j++ {
		/* CCj = AES-enc(K; CCCj) */
		aesTransform(C[j*16:(j+1)*16], C[j*16:(j+1)*16], direction, bc)
		/* Cj = 2**(j-1)*L xor CCj */
		xorBlocks(C[j*16:(j+1)*16], C[j*16:(j+1)*16], LTable[j])
	}

	return C
}
<|endoftext|>