<commit_before>package shell

import (
	"context"
	"flag"
	"fmt"
	"io"
	"sort"
	"sync"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/operation"
	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"github.com/chrislusf/seaweedfs/weed/pb/volume_server_pb"
	"github.com/chrislusf/seaweedfs/weed/storage/erasure_coding"
	"github.com/chrislusf/seaweedfs/weed/storage/needle"
	"github.com/chrislusf/seaweedfs/weed/wdclient"
	"google.golang.org/grpc"
)

func init() {
	commands = append(commands, &commandEcEncode{})
}

type commandEcEncode struct {
}

func (c *commandEcEncode) Name() string {
	return "ec.encode"
}

func (c *commandEcEncode) Help() string {
	return `apply erasure coding to a volume

	This command will:
	1. freeze one volume
	2. apply erasure coding to the volume
	3. move the encoded shards to multiple volume servers

	The erasure coding is 10.4. So ideally you have more than 14 volume servers, and you can afford
	to lose 4 volume servers.

	If the number of volumes are not high, the worst case is that you only have 4 volume servers,
	and the shards are spread as 4,4,3,3, respectively. You can afford to lose one volume server.

	If you only have less than 4 volume servers, with erasure coding, at least you can afford to
	have 4 corrupted shard files.

`
}

func (c *commandEcEncode) Do(args []string, commandEnv *commandEnv, writer io.Writer) (err error) {

	encodeCommand := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
	volumeId := encodeCommand.Int("volumeId", 0, "the volume id")
	collection := encodeCommand.String("collection", "", "the collection name")
	if err = encodeCommand.Parse(args); err != nil {
		return nil
	}

	ctx := context.Background()

	// find volume location
	locations := commandEnv.masterClient.GetLocations(uint32(*volumeId))
	if len(locations) == 0 {
		return fmt.Errorf("volume %d not found", *volumeId)
	}

	// generate ec shards
	err = generateEcShards(ctx, commandEnv.option.GrpcDialOption, needle.VolumeId(*volumeId), *collection, locations[0].Url)
	if err != nil {
		return fmt.Errorf("generate ec shards for volume %d on %s: %v", *volumeId, locations[0].Url, err)
	}

	// balance the ec shards to current cluster
	err = balanceEcShards(ctx, commandEnv, needle.VolumeId(*volumeId), *collection, locations)
	if err != nil {
		return fmt.Errorf("balance ec shards for volume %d on %s: %v", *volumeId, locations[0].Url, err)
	}

	return err
}

func generateEcShards(ctx context.Context, grpcDialOption grpc.DialOption, volumeId needle.VolumeId, collection string, sourceVolumeServer string) error {

	err := operation.WithVolumeServerClient(sourceVolumeServer, grpcDialOption, func(volumeServerClient volume_server_pb.VolumeServerClient) error {
		_, genErr := volumeServerClient.VolumeEcShardsGenerate(ctx, &volume_server_pb.VolumeEcShardsGenerateRequest{
			VolumeId:   uint32(volumeId),
			Collection: collection,
		})
		return genErr
	})

	return err

}

func balanceEcShards(ctx context.Context, commandEnv *commandEnv, volumeId needle.VolumeId, collection string, existingLocations []wdclient.Location) (err error) {

	allEcNodes, totalFreeEcSlots, err := collectEcNodes(ctx, commandEnv)
	if err != nil {
		return err
	}

	if totalFreeEcSlots < erasure_coding.TotalShardsCount {
		return fmt.Errorf("not enough free ec shard slots. only %d left", totalFreeEcSlots)
	}
	allocatedDataNodes := allEcNodes
	if len(allocatedDataNodes) > erasure_coding.TotalShardsCount {
		allocatedDataNodes = allocatedDataNodes[:erasure_coding.TotalShardsCount]
	}

	// calculate how many shards to allocate for these servers
	allocated := balancedEcDistribution(allocatedDataNodes)

	// ask the data nodes to copy from the source volume server
	copiedShardIds, err := parallelCopyEcShardsFromSource(ctx, commandEnv.option.GrpcDialOption, allocatedDataNodes, allocated, volumeId, collection, existingLocations[0])
	if err != nil {
		return nil
	}

	// ask the source volume server to clean up copied ec shards
	err = sourceServerDeleteEcShards(ctx, commandEnv.option.GrpcDialOption, volumeId, existingLocations[0], copiedShardIds)
	if err != nil {
		return fmt.Errorf("sourceServerDeleteEcShards %s %d.%v: %v", existingLocations[0], volumeId, copiedShardIds, err)
	}

	// ask the source volume server to delete the original volume
	for _, location := range existingLocations {
		err = deleteVolume(ctx, commandEnv.option.GrpcDialOption, volumeId, location.Url)
		if err != nil {
			return fmt.Errorf("deleteVolume %s volume %d: %v", location.Url, volumeId, err)
		}
	}

	return err

}

func parallelCopyEcShardsFromSource(ctx context.Context, grpcDialOption grpc.DialOption,
	targetServers []*EcNode, allocated []int,
	volumeId needle.VolumeId, collection string, existingLocation wdclient.Location) (actuallyCopied []uint32, err error) {

	// parallelize
	shardIdChan := make(chan []uint32, len(targetServers))
	var wg sync.WaitGroup
	startFromShardId := uint32(0)
	for i, server := range targetServers {
		if allocated[i] <= 0 {
			continue
		}

		wg.Add(1)
		go func(server *EcNode, startFromShardId uint32, shardCount int) {
			defer wg.Done()
			copiedShardIds, copyErr := oneServerCopyEcShardsFromSource(ctx, grpcDialOption, server,
				startFromShardId, shardCount, volumeId, collection, existingLocation)
			if copyErr != nil {
				err = copyErr
			} else {
				shardIdChan <- copiedShardIds
				server.freeEcSlot -= len(copiedShardIds)
			}
		}(server, startFromShardId, allocated[i])
		startFromShardId += uint32(allocated[i])
	}
	wg.Wait()
	close(shardIdChan)

	if err != nil {
		return nil, err
	}

	for shardIds := range shardIdChan {
		actuallyCopied = append(actuallyCopied, shardIds...)
	}

	return
}

func oneServerCopyEcShardsFromSource(ctx context.Context, grpcDialOption grpc.DialOption,
	targetServer *EcNode, startFromShardId uint32, shardCount int,
	volumeId needle.VolumeId, collection string, existingLocation wdclient.Location) (copiedShardIds []uint32, err error) {

	var shardIdsToCopy []uint32
	for shardId := startFromShardId; shardId < startFromShardId+uint32(shardCount); shardId++ {
		fmt.Printf("allocate %d.%d %s => %s\n", volumeId, shardId, existingLocation.Url, targetServer.info.Id)
		shardIdsToCopy = append(shardIdsToCopy, shardId)
	}

	err = operation.WithVolumeServerClient(targetServer.info.Id, grpcDialOption, func(volumeServerClient volume_server_pb.VolumeServerClient) error {

		if targetServer.info.Id != existingLocation.Url {

			_, copyErr := volumeServerClient.VolumeEcShardsCopy(ctx, &volume_server_pb.VolumeEcShardsCopyRequest{
				VolumeId:       uint32(volumeId),
				Collection:     collection,
				ShardIds:       shardIdsToCopy,
				SourceDataNode: existingLocation.Url,
			})
			if copyErr != nil {
				return copyErr
			}
		}

		_, mountErr := volumeServerClient.VolumeEcShardsMount(ctx, &volume_server_pb.VolumeEcShardsMountRequest{
			VolumeId:   uint32(volumeId),
			Collection: collection,
			ShardIds:   shardIdsToCopy,
		})
		if mountErr != nil {
			return mountErr
		}

		if targetServer.info.Id != existingLocation.Url {
			copiedShardIds = shardIdsToCopy
			glog.V(0).Infof("%s ec volume %d deletes shards %+v", existingLocation.Url, volumeId, copiedShardIds)
		}

		return nil
	})

	if err != nil {
		return
	}

	return
}

func sourceServerDeleteEcShards(ctx context.Context, grpcDialOption grpc.DialOption,
	volumeId needle.VolumeId, sourceLocation wdclient.Location, toBeDeletedShardIds []uint32) error {

	shouldDeleteEcx := len(toBeDeletedShardIds) == erasure_coding.TotalShardsCount

	return operation.WithVolumeServerClient(sourceLocation.Url, grpcDialOption, func(volumeServerClient volume_server_pb.VolumeServerClient) error {
		_, deleteErr := volumeServerClient.VolumeEcShardsDelete(ctx, &volume_server_pb.VolumeEcShardsDeleteRequest{
			VolumeId:        uint32(volumeId),
			ShardIds:        toBeDeletedShardIds,
			ShouldDeleteEcx: shouldDeleteEcx,
		})
		return deleteErr
	})

}

func balancedEcDistribution(servers []*EcNode) (allocated []int) {
	freeSlots := make([]int, len(servers))
	allocated = make([]int, len(servers))
	for i, server := range servers {
		freeSlots[i] = countFreeShardSlots(server.info)
	}
	allocatedCount := 0
	for allocatedCount < erasure_coding.TotalShardsCount {
		for i, _ := range servers {
			if freeSlots[i]-allocated[i] > 0 {
				allocated[i] += 1
				allocatedCount += 1
			}
			if allocatedCount >= erasure_coding.TotalShardsCount {
				break
			}
		}
	}

	return allocated
}

func eachDataNode(topo *master_pb.TopologyInfo, fn func(*master_pb.DataNodeInfo)) {
	for _, dc := range topo.DataCenterInfos {
		for _, rack := range dc.RackInfos {
			for _, dn := range rack.DataNodeInfos {
				fn(dn)
			}
		}
	}
}

func countShards(ecShardInfos []*master_pb.VolumeEcShardInformationMessage) (count int) {
	for _, ecShardInfo := range ecShardInfos {
		shardBits := erasure_coding.ShardBits(ecShardInfo.EcIndexBits)
		count += shardBits.ShardIdCount()
	}
	return
}

func countFreeShardSlots(dn *master_pb.DataNodeInfo) (count int) {
	return int(dn.FreeVolumeCount)*10 - countShards(dn.EcShardInfos)
}

type EcNode struct {
	info       *master_pb.DataNodeInfo
	freeEcSlot int
}

func sortEcNodes(ecNodes []*EcNode) {
	sort.Slice(ecNodes, func(i, j int) bool {
		return ecNodes[i].freeEcSlot > ecNodes[j].freeEcSlot
	})
}

func collectEcNodes(ctx context.Context, commandEnv *commandEnv) (ecNodes []*EcNode, totalFreeEcSlots int, err error) {

	// list all possible locations
	var resp *master_pb.VolumeListResponse
	err = commandEnv.masterClient.WithClient(ctx, func(client master_pb.SeaweedClient) error {
		resp, err = client.VolumeList(ctx, &master_pb.VolumeListRequest{})
		return err
	})
	if err != nil {
		return nil, 0, err
	}

	// find out all volume servers with one slot left.
	eachDataNode(resp.TopologyInfo, func(dn *master_pb.DataNodeInfo) {
		if freeEcSlots := countFreeShardSlots(dn); freeEcSlots > 0 {
			ecNodes = append(ecNodes, &EcNode{
				info:       dn,
				freeEcSlot: int(freeEcSlots),
			})
			totalFreeEcSlots += freeEcSlots
		}
	})

	sortEcNodes(ecNodes)

	return
}
<commit_msg>encode by collection<commit_after>package shell

import (
	"context"
	"flag"
	"fmt"
	"io"
	"sort"
	"sync"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/operation"
	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"github.com/chrislusf/seaweedfs/weed/pb/volume_server_pb"
	"github.com/chrislusf/seaweedfs/weed/storage/erasure_coding"
	"github.com/chrislusf/seaweedfs/weed/storage/needle"
	"github.com/chrislusf/seaweedfs/weed/wdclient"
	"google.golang.org/grpc"
)

func init() {
	commands = append(commands, &commandEcEncode{})
}

type commandEcEncode struct {
}

func (c *commandEcEncode) Name() string {
	return "ec.encode"
}

func (c *commandEcEncode) Help() string {
	return `apply erasure coding to a volume

	This command will:
	1. freeze one volume
	2. apply erasure coding to the volume
	3. move the encoded shards to multiple volume servers

	The erasure coding is 10.4. So ideally you have more than 14 volume servers, and you can afford
	to lose 4 volume servers.

	If the number of volumes are not high, the worst case is that you only have 4 volume servers,
	and the shards are spread as 4,4,3,3, respectively. You can afford to lose one volume server.

	If you only have less than 4 volume servers, with erasure coding, at least you can afford to
	have 4 corrupted shard files.

`
}

func (c *commandEcEncode) Do(args []string, commandEnv *commandEnv, writer io.Writer) (err error) {

	encodeCommand := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
	volumeId := encodeCommand.Int("volumeId", 0, "the volume id")
	collection := encodeCommand.String("collection", "", "the collection name")
	if err = encodeCommand.Parse(args); err != nil {
		return nil
	}

	ctx := context.Background()
	vid := needle.VolumeId(*volumeId)

	// volumeId is provided
	if vid != 0 {
		return doEcEncode(ctx, commandEnv, *collection, vid)
	}

	// apply to all volumes in the collection
	volumeIds, err := collectVolumeByCollection(ctx, commandEnv, *collection)
	if err != nil {
		return err
	}
	for _, vid := range volumeIds {
		if err = doEcEncode(ctx, commandEnv, *collection, vid); err != nil {
			return err
		}
	}

	return nil
}

func doEcEncode(ctx context.Context, commandEnv *commandEnv, collection string, vid needle.VolumeId) (err error) {
	// find volume location
	locations := commandEnv.masterClient.GetLocations(uint32(vid))
	if len(locations) == 0 {
		return fmt.Errorf("volume %d not found", vid)
	}

	// generate ec shards
	err = generateEcShards(ctx, commandEnv.option.GrpcDialOption, needle.VolumeId(vid), collection, locations[0].Url)
	if err != nil {
		return fmt.Errorf("generate ec shards for volume %d on %s: %v", vid, locations[0].Url, err)
	}

	// balance the ec shards to current cluster
	err = balanceEcShards(ctx, commandEnv, vid, collection, locations)
	if err != nil {
		return fmt.Errorf("balance ec shards for volume %d on %s: %v", vid, locations[0].Url, err)
	}

	return nil
}

func generateEcShards(ctx context.Context, grpcDialOption grpc.DialOption, volumeId needle.VolumeId, collection string, sourceVolumeServer string) error {

	err := operation.WithVolumeServerClient(sourceVolumeServer, grpcDialOption, func(volumeServerClient volume_server_pb.VolumeServerClient) error {
		_, genErr := volumeServerClient.VolumeEcShardsGenerate(ctx, &volume_server_pb.VolumeEcShardsGenerateRequest{
			VolumeId:   uint32(volumeId),
			Collection: collection,
		})
		return genErr
	})

	return err

}

func balanceEcShards(ctx context.Context, commandEnv *commandEnv, volumeId needle.VolumeId, collection string, existingLocations []wdclient.Location) (err error) {

	allEcNodes, totalFreeEcSlots, err := collectEcNodes(ctx, commandEnv)
	if err != nil {
		return err
	}

	if totalFreeEcSlots < erasure_coding.TotalShardsCount {
		return fmt.Errorf("not enough free ec shard slots. only %d left", totalFreeEcSlots)
	}
	allocatedDataNodes := allEcNodes
	if len(allocatedDataNodes) > erasure_coding.TotalShardsCount {
		allocatedDataNodes = allocatedDataNodes[:erasure_coding.TotalShardsCount]
	}

	// calculate how many shards to allocate for these servers
	allocated := balancedEcDistribution(allocatedDataNodes)

	// ask the data nodes to copy from the source volume server
	copiedShardIds, err := parallelCopyEcShardsFromSource(ctx, commandEnv.option.GrpcDialOption, allocatedDataNodes, allocated, volumeId, collection, existingLocations[0])
	if err != nil {
		return nil
	}

	// ask the source volume server to clean up copied ec shards
	err = sourceServerDeleteEcShards(ctx, commandEnv.option.GrpcDialOption, volumeId, existingLocations[0], copiedShardIds)
	if err != nil {
		return fmt.Errorf("sourceServerDeleteEcShards %s %d.%v: %v", existingLocations[0], volumeId, copiedShardIds, err)
	}

	// ask the source volume server to delete the original volume
	for _, location := range existingLocations {
		err = deleteVolume(ctx, commandEnv.option.GrpcDialOption, volumeId, location.Url)
		if err != nil {
			return fmt.Errorf("deleteVolume %s volume %d: %v", location.Url, volumeId, err)
		}
	}

	return err

}

func parallelCopyEcShardsFromSource(ctx context.Context, grpcDialOption grpc.DialOption,
	targetServers []*EcNode, allocated []int,
	volumeId needle.VolumeId, collection string, existingLocation wdclient.Location) (actuallyCopied []uint32, err error) {

	// parallelize
	shardIdChan := make(chan []uint32, len(targetServers))
	var wg sync.WaitGroup
	startFromShardId := uint32(0)
	for i, server := range targetServers {
		if allocated[i] <= 0 {
			continue
		}

		wg.Add(1)
		go func(server *EcNode, startFromShardId uint32, shardCount int) {
			defer wg.Done()
			copiedShardIds, copyErr := oneServerCopyEcShardsFromSource(ctx, grpcDialOption, server,
				startFromShardId, shardCount, volumeId, collection, existingLocation)
			if copyErr != nil {
				err = copyErr
			} else {
				shardIdChan <- copiedShardIds
				server.freeEcSlot -= len(copiedShardIds)
			}
		}(server, startFromShardId, allocated[i])
		startFromShardId += uint32(allocated[i])
	}
	wg.Wait()
	close(shardIdChan)

	if err != nil {
		return nil, err
	}

	for shardIds := range shardIdChan {
		actuallyCopied = append(actuallyCopied, shardIds...)
	}

	return
}

func oneServerCopyEcShardsFromSource(ctx context.Context, grpcDialOption grpc.DialOption,
	targetServer *EcNode, startFromShardId uint32, shardCount int,
	volumeId needle.VolumeId, collection string, existingLocation wdclient.Location) (copiedShardIds []uint32, err error) {

	var shardIdsToCopy []uint32
	for shardId := startFromShardId; shardId < startFromShardId+uint32(shardCount); shardId++ {
		fmt.Printf("allocate %d.%d %s => %s\n", volumeId, shardId, existingLocation.Url, targetServer.info.Id)
		shardIdsToCopy = append(shardIdsToCopy, shardId)
	}

	err = operation.WithVolumeServerClient(targetServer.info.Id, grpcDialOption, func(volumeServerClient volume_server_pb.VolumeServerClient) error {

		if targetServer.info.Id != existingLocation.Url {

			_, copyErr := volumeServerClient.VolumeEcShardsCopy(ctx, &volume_server_pb.VolumeEcShardsCopyRequest{
				VolumeId:       uint32(volumeId),
				Collection:     collection,
				ShardIds:       shardIdsToCopy,
				SourceDataNode: existingLocation.Url,
			})
			if copyErr != nil {
				return copyErr
			}
		}

		_, mountErr := volumeServerClient.VolumeEcShardsMount(ctx, &volume_server_pb.VolumeEcShardsMountRequest{
			VolumeId:   uint32(volumeId),
			Collection: collection,
			ShardIds:   shardIdsToCopy,
		})
		if mountErr != nil {
			return mountErr
		}

		if targetServer.info.Id != existingLocation.Url {
			copiedShardIds = shardIdsToCopy
			glog.V(0).Infof("%s ec volume %d deletes shards %+v", existingLocation.Url, volumeId, copiedShardIds)
		}

		return nil
	})

	if err != nil {
		return
	}

	return
}

func sourceServerDeleteEcShards(ctx context.Context, grpcDialOption grpc.DialOption,
	volumeId needle.VolumeId, sourceLocation wdclient.Location, toBeDeletedShardIds []uint32) error {

	shouldDeleteEcx := len(toBeDeletedShardIds) == erasure_coding.TotalShardsCount

	return operation.WithVolumeServerClient(sourceLocation.Url, grpcDialOption, func(volumeServerClient volume_server_pb.VolumeServerClient) error {
		_, deleteErr := volumeServerClient.VolumeEcShardsDelete(ctx, &volume_server_pb.VolumeEcShardsDeleteRequest{
			VolumeId:        uint32(volumeId),
			ShardIds:        toBeDeletedShardIds,
			ShouldDeleteEcx: shouldDeleteEcx,
		})
		return deleteErr
	})

}

func balancedEcDistribution(servers []*EcNode) (allocated []int) {
	freeSlots := make([]int, len(servers))
	allocated = make([]int, len(servers))
	for i, server := range servers {
		freeSlots[i] = countFreeShardSlots(server.info)
	}
	allocatedCount := 0
	for allocatedCount < erasure_coding.TotalShardsCount {
		for i, _ := range servers {
			if freeSlots[i]-allocated[i] > 0 {
				allocated[i] += 1
				allocatedCount += 1
			}
			if allocatedCount >= erasure_coding.TotalShardsCount {
				break
			}
		}
	}

	return allocated
}

func eachDataNode(topo *master_pb.TopologyInfo, fn func(*master_pb.DataNodeInfo)) {
	for _, dc := range topo.DataCenterInfos {
		for _, rack := range dc.RackInfos {
			for _, dn := range rack.DataNodeInfos {
				fn(dn)
			}
		}
	}
}

func countShards(ecShardInfos []*master_pb.VolumeEcShardInformationMessage) (count int) {
	for _, ecShardInfo := range ecShardInfos {
		shardBits := erasure_coding.ShardBits(ecShardInfo.EcIndexBits)
		count += shardBits.ShardIdCount()
	}
	return
}

func countFreeShardSlots(dn *master_pb.DataNodeInfo) (count int) {
	return int(dn.FreeVolumeCount)*10 - countShards(dn.EcShardInfos)
}

type EcNode struct {
	info       *master_pb.DataNodeInfo
	freeEcSlot int
}

func sortEcNodes(ecNodes []*EcNode) {
	sort.Slice(ecNodes, func(i, j int) bool {
		return ecNodes[i].freeEcSlot > ecNodes[j].freeEcSlot
	})
}

func collectEcNodes(ctx context.Context, commandEnv *commandEnv) (ecNodes []*EcNode, totalFreeEcSlots int, err error) {

	// list all possible locations
	var resp *master_pb.VolumeListResponse
	err = commandEnv.masterClient.WithClient(ctx, func(client master_pb.SeaweedClient) error {
		resp, err = client.VolumeList(ctx, &master_pb.VolumeListRequest{})
		return err
	})
	if err != nil {
		return nil, 0, err
	}

	// find out all volume servers with one slot left.
	eachDataNode(resp.TopologyInfo, func(dn *master_pb.DataNodeInfo) {
		if freeEcSlots := countFreeShardSlots(dn); freeEcSlots > 0 {
			ecNodes = append(ecNodes, &EcNode{
				info:       dn,
				freeEcSlot: int(freeEcSlots),
			})
			totalFreeEcSlots += freeEcSlots
		}
	})

	sortEcNodes(ecNodes)

	return
}

func collectVolumeByCollection(ctx context.Context, commandEnv *commandEnv, selectedCollection string) (vids []needle.VolumeId, err error) {

	var resp *master_pb.VolumeListResponse
	err = commandEnv.masterClient.WithClient(ctx, func(client master_pb.SeaweedClient) error {
		resp, err = client.VolumeList(ctx, &master_pb.VolumeListRequest{})
		return err
	})
	if err != nil {
		return
	}

	vidMap := make(map[uint32]bool)
	for _, dc := range resp.TopologyInfo.DataCenterInfos {
		for _, r := range dc.RackInfos {
			for _, dn := range r.DataNodeInfos {
				for _, v := range dn.VolumeInfos {
					if v.Collection == selectedCollection {
						vidMap[v.Id] = true
					}
				}
			}
		}
	}

	for vid, _ := range vidMap {
		vids = append(vids, needle.VolumeId(vid))
	}

	return
}
<|endoftext|>


<commit_before>// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// Package grand provides high performance random string generation functionality.
package grand

import (
	"encoding/binary"
	"unsafe"
)

var (
	letters    = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // 52
	symbols    = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"                   // 32
	digits     = "0123456789"                                           // 10
	characters = letters + digits + symbols                             // 94
)

// Meet randomly calculate whether the given probability <num>/<total> is met.
func Meet(num, total int) bool {
	return Intn(total) < num
}

// MeetProb randomly calculate whether the given probability is met.
func MeetProb(prob float32) bool {
	return Intn(1e7) < int(prob*1e7)
}

// B retrieves and returns random bytes of given length <n>.
func B(n int) []byte {
	if n <= 0 {
		return nil
	}
	i := 0
	b := make([]byte, n)
	for {
		copy(b[i:], <-bufferChan)
		i += 4
		if i >= n {
			break
		}
	}
	return b
}

// N returns a random int between min and max: [min, max].
// The <min> and <max> also support negative numbers.
func N(min, max int) int {
	if min >= max {
		return min
	}
	if min >= 0 {
		// Because Intn dose not support negative number,
		// so we should first shift the value to left,
		// then call Intn to produce the random number,
		// and finally shift the result back to right.
		return Intn(max-(min-0)+1) + (min - 0)
	}
	if min < 0 {
		// Because Intn dose not support negative number,
		// so we should first shift the value to right,
		// then call Intn to produce the random number,
		// and finally shift the result back to left.
		return Intn(max+(0-min)+1) - (0 - min)
	}
	return 0
}

// S returns a random string which contains digits and letters, and its length is <n>.
// The optional parameter <symbols> specifies whether the result could contain symbols,
// which is false in default.
func S(n int, symbols ...bool) string {
	b := make([]byte, n)
	for i := range b {
		if len(symbols) > 0 && symbols[0] {
			b[i] = characters[Intn(94)]
		} else {
			b[i] = characters[Intn(62)]
		}
	}
	return *(*string)(unsafe.Pointer(&b))
}

// Str randomly picks and returns <n> count of chars from given string <s>.
// It also supports unicode string like Chinese/Russian/Japanese, etc.
func Str(s string, n int) string {
	b := make([]rune, n)
	runes := []rune(s)
	for i := range b {
		b[i] = runes[Intn(len(runes))]
	}
	return string(b)
}

// Digits returns a random string which contains only digits, and its length is <n>.
func Digits(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = digits[Intn(10)]
	}
	return *(*string)(unsafe.Pointer(&b))
}

// Letters returns a random string which contains only letters, and its length is <n>.
func Letters(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = letters[Intn(52)]
	}
	return *(*string)(unsafe.Pointer(&b))
}

// Symbols returns a random string which contains only symbols, and its length is <n>.
func Symbols(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = symbols[Intn(52)]
	}
	return *(*string)(unsafe.Pointer(&b))
}

// Perm returns, as a slice of n int numbers, a pseudo-random permutation of the integers [0,n).
// TODO performance improving for large slice producing.
func Perm(n int) []int {
	m := make([]int, n)
	for i := 0; i < n; i++ {
		j := Intn(i + 1)
		m[i] = m[j]
		m[j] = i
	}
	return m
}

// Intn returns a int number which is between 0 and max: [0, max).
//
// Note that:
// 1. The <max> can only be greater than 0, or else it returns <max> directly;
// 2. The result is greater than or equal to 0, but less than <max>;
// 3. The result number is 32bit and less than math.MaxUint32.
func Intn(max int) int {
	if max <= 0 {
		return max
	}
	n := int(binary.LittleEndian.Uint32(<-bufferChan)) % max
	if (max > 0 && n < 0) || (max < 0 && n > 0) {
		return -n
	}
	return n
}
<commit_msg>comment update for package grand<commit_after>// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// Package grand provides high performance random bytes/number/string generation functionality.
package grand

import (
	"encoding/binary"
	"unsafe"
)

var (
	letters    = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // 52
	symbols    = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"                   // 32
	digits     = "0123456789"                                           // 10
	characters = letters + digits + symbols                             // 94
)

// Meet randomly calculate whether the given probability <num>/<total> is met.
func Meet(num, total int) bool {
	return Intn(total) < num
}

// MeetProb randomly calculate whether the given probability is met.
func MeetProb(prob float32) bool {
	return Intn(1e7) < int(prob*1e7)
}

// B retrieves and returns random bytes of given length <n>.
func B(n int) []byte {
	if n <= 0 {
		return nil
	}
	i := 0
	b := make([]byte, n)
	for {
		copy(b[i:], <-bufferChan)
		i += 4
		if i >= n {
			break
		}
	}
	return b
}

// N returns a random int between min and max: [min, max].
// The <min> and <max> also support negative numbers.
func N(min, max int) int {
	if min >= max {
		return min
	}
	if min >= 0 {
		// Because Intn dose not support negative number,
		// so we should first shift the value to left,
		// then call Intn to produce the random number,
		// and finally shift the result back to right.
		return Intn(max-(min-0)+1) + (min - 0)
	}
	if min < 0 {
		// Because Intn dose not support negative number,
		// so we should first shift the value to right,
		// then call Intn to produce the random number,
		// and finally shift the result back to left.
		return Intn(max+(0-min)+1) - (0 - min)
	}
	return 0
}

// S returns a random string which contains digits and letters, and its length is <n>.
// The optional parameter <symbols> specifies whether the result could contain symbols,
// which is false in default.
func S(n int, symbols ...bool) string {
	b := make([]byte, n)
	for i := range b {
		if len(symbols) > 0 && symbols[0] {
			b[i] = characters[Intn(94)]
		} else {
			b[i] = characters[Intn(62)]
		}
	}
	return *(*string)(unsafe.Pointer(&b))
}

// Str randomly picks and returns <n> count of chars from given string <s>.
// It also supports unicode string like Chinese/Russian/Japanese, etc.
func Str(s string, n int) string {
	b := make([]rune, n)
	runes := []rune(s)
	for i := range b {
		b[i] = runes[Intn(len(runes))]
	}
	return string(b)
}

// Digits returns a random string which contains only digits, and its length is <n>.
func Digits(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = digits[Intn(10)]
	}
	return *(*string)(unsafe.Pointer(&b))
}

// Letters returns a random string which contains only letters, and its length is <n>.
func Letters(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = letters[Intn(52)]
	}
	return *(*string)(unsafe.Pointer(&b))
}

// Symbols returns a random string which contains only symbols, and its length is <n>.
func Symbols(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = symbols[Intn(52)]
	}
	return *(*string)(unsafe.Pointer(&b))
}

// Perm returns, as a slice of n int numbers, a pseudo-random permutation of the integers [0,n).
// TODO performance improving for large slice producing.
func Perm(n int) []int {
	m := make([]int, n)
	for i := 0; i < n; i++ {
		j := Intn(i + 1)
		m[i] = m[j]
		m[j] = i
	}
	return m
}

// Intn returns a int number which is between 0 and max: [0, max).
//
// Note that:
// 1. The <max> can only be greater than 0, or else it returns <max> directly;
// 2. The result is greater than or equal to 0, but less than <max>;
// 3. The result number is 32bit and less than math.MaxUint32.
func Intn(max int) int {
	if max <= 0 {
		return max
	}
	n := int(binary.LittleEndian.Uint32(<-bufferChan)) % max
	if (max > 0 && n < 0) || (max < 0 && n > 0) {
		return -n
	}
	return n
}
<|endoftext|>


<commit_before>package upcloud

import (
	"fmt"
	"testing"

	"github.com/UpCloudLtd/upcloud-go-api/upcloud"
	"github.com/UpCloudLtd/upcloud-go-api/upcloud/request"
	"github.com/UpCloudLtd/upcloud-go-api/upcloud/service"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

const firewallRulesResourceName = "upcloud_firewall_rules.my_rule"

func TestUpcloudFirewallRules_basic(t *testing.T) {
	var providers []*schema.Provider
	var firewallRules upcloud.FirewallRules
	resourceName := firewallRulesResourceName

	resource.Test(t, resource.TestCase{
		PreCheck:          func() { testAccPreCheck(t) },
		ProviderFactories: testAccProviderFactories(&providers),
		CheckDestroy:      testAccCheckFirewallRulesDestroy,
		Steps: []resource.TestStep{
			{
				Config: testUpcloudFirewallRulesInstanceConfig(),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(resourceName, "firewall_rule.#", "1"),
					testAccCheckFirewallRulesExists(resourceName, &firewallRules),
					testAccCheckUpCloudFirewallRuleAttributes(&firewallRules, 0, "accept",
						"Allow SSH from this network",
						"IPv4",
						"",
						"tcp",
						"in",
						"",
						"",
						"22",
						"22",
						"192.168.1.1",
						"192.168.1.255",
						"",
						""),
				),
			},
		},
	})
}

func TestUpcloudFirewallRules_update(t *testing.T) {
	var providers []*schema.Provider

	var firewallRules upcloud.FirewallRules
	resourceName := "upcloud_firewall_rules.my_server"

	resource.Test(t, resource.TestCase{
		PreCheck:          func() { testAccPreCheck(t) },
		ProviderFactories: testAccProviderFactories(&providers),
		CheckDestroy:      testAccCheckFirewallRulesDestroy,
		Steps: []resource.TestStep{
			{
				Config: testUpcloudFirewallRulesInstanceConfig(),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(resourceName, "firewall_rule.#", "1"),
					testAccCheckFirewallRulesExists(resourceName, &firewallRules),
				),
			},
			{
				Config: testUpcloudFirewallRulesInstanceConfigUpdate(),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(resourceName, "firewall_rule.#", "2"),
					testAccCheckFirewallRulesExists(resourceName, &firewallRules),
				),
			},
		},
	})
}

func TestUpcloudFirewallRules_import(t *testing.T) {
	var providers []*schema.Provider

	var firewallRules upcloud.FirewallRules
	resourceName := firewallRulesResourceName

	resource.Test(t, resource.TestCase{
		PreCheck:          func() { testAccPreCheck(t) },
		ProviderFactories: testAccProviderFactories(&providers),
		CheckDestroy:      testAccCheckFirewallRulesDestroy,
		Steps: []resource.TestStep{
			{
				Config: testUpcloudFirewallRulesInstanceConfig(),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckFirewallRulesExists(resourceName, &firewallRules),
				),
			},
			{
				ResourceName:            resourceName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"server_id"},
			},
		},
	})
}

func testAccCheckFirewallRulesDestroy(s *terraform.State) error {
	for _, rs := range s.RootModule().Resources {
		if rs.Type != "upcloud_firewall_rules" {
			continue
		}

		client := testAccProvider.Meta().(*service.Service)

		_, err := client.GetFirewallRules(&request.GetFirewallRulesRequest{
			ServerUUID: rs.Primary.ID,
		})
		if err == nil {
			return fmt.Errorf(
				"Error firewall rules still exists after deletion for server (%s)",
				rs.Primary.ID,
			)
		}
	}

	return nil
}

func testAccCheckFirewallRulesExists(resourceName string, firewallRules *upcloud.FirewallRules) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		// Look for the full resource name and error if not found
		rs, ok := s.RootModule().Resources[resourceName]
		if !ok {
			return fmt.Errorf("Not found: %s", resourceName)
		}

		// The provider has not set the ID for the resource
		if rs.Primary.ID == "" {
			return fmt.Errorf("No Firewall ID is set")
		}

		client := testAccProvider.Meta().(*service.Service)
		latest, err := client.GetFirewallRules(&request.GetFirewallRulesRequest{
			ServerUUID: rs.Primary.ID,
		})

		if err != nil {
			return err
		}

		// Update the reference the remote located storage
		*firewallRules = *latest

		return nil
	}
}

func testAccCheckUpCloudFirewallRuleAttributes(firewallRules *upcloud.FirewallRules, index int, action, comment, family, icmpType, protocol, direction, destinationAddressStart, destinationAddressEnd, destinationPortStart, destinationPortEnd, sourceAddressStart, sourceAddressEnd, sourcePortStart, sourcePortEnd string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		firewallRule := firewallRules.FirewallRules[index]

		if firewallRule.Action != action {
			return fmt.Errorf("Bad action, expected (%s), got (%s)", action, firewallRule.Action)
		}

		if firewallRule.Comment != comment {
			return fmt.Errorf("Bad comment, expected (%s), got (%s)", comment, firewallRule.Comment)
		}

		if firewallRule.Family != family {
			return fmt.Errorf("Bad family, expected (%s), got (%s)", family, firewallRule.Family)
		}

		if firewallRule.ICMPType != icmpType {
			return fmt.Errorf("Bad icmpType, expected (%s), got (%s)", icmpType, firewallRule.ICMPType)
		}

		if firewallRule.Protocol != protocol {
			return fmt.Errorf("Bad protocol, expected (%s), got (%s)", protocol, firewallRule.Protocol)
		}

		if firewallRule.Direction != direction {
			return fmt.Errorf("Bad direction, expected (%s), got (%s)", direction, firewallRule.Direction)
		}

		if firewallRule.DestinationAddressStart != destinationAddressStart {
			return fmt.Errorf("Bad destination_address_start, expected (%s), got (%s)", destinationAddressStart, firewallRule.DestinationAddressStart)
		}

		if firewallRule.DestinationAddressEnd != destinationAddressEnd {
			return fmt.Errorf("Bad destination_address_end, expected (%s), got (%s)", destinationAddressEnd, firewallRule.DestinationAddressEnd)
		}

		if firewallRule.DestinationPortStart != destinationPortStart {
			return fmt.Errorf("Bad destination_port_start, expected (%s), got (%s)", destinationPortStart, firewallRule.DestinationPortStart)
		}

		if firewallRule.DestinationPortEnd != destinationPortEnd {
			return fmt.Errorf("Bad destination_port_end, expected (%s), got (%s)", destinationPortEnd, firewallRule.DestinationPortEnd)
		}

		if firewallRule.SourceAddressStart != sourceAddressStart {
			return fmt.Errorf("Bad source_address_start, expected (%s), got (%s)", sourceAddressStart, firewallRule.SourceAddressStart)
		}

		if firewallRule.SourceAddressEnd != sourceAddressEnd {
			return fmt.Errorf("Bad source_address_end, expected (%s), got (%s)", sourceAddressEnd, firewallRule.SourceAddressEnd)
		}

		if firewallRule.SourcePortStart != sourcePortStart {
			return fmt.Errorf("Bad source_port_start, expected (%s), got (%s)", sourcePortStart, firewallRule.SourcePortStart)
		}

		if firewallRule.SourcePortEnd != sourcePortEnd {
			return fmt.Errorf("Bad source_port_end, expected (%s), got (%s)", sourcePortEnd, firewallRule.SourcePortEnd)
		}

		return nil
	}
}

func testUpcloudFirewallRulesInstanceConfig() string {
	return `
		resource "upcloud_server" "my_server" {
		  zone     = "fi-hel1"
		  hostname = "debian.example.com"
		  plan     = "1xCPU-2GB"

		  template {
			storage = "01000000-0000-4000-8000-000020050100"
			size = 10
		  }

		  network_interface {
			type = "utility"
		  }

		}

		resource "upcloud_firewall_rules" "my_rule" {
		  server_id = upcloud_server.my_server.id

		  firewall_rule {
			action = "accept"
			comment = "Allow SSH from this network"
			destination_address_end = ""
			destination_address_start = ""
			destination_port_end = 22
			destination_port_start = 22
			direction = "in"
			family = "IPv4"
			icmp_type = ""
			protocol = "tcp"
			source_address_end = "192.168.1.255"
			source_address_start = "192.168.1.1"
		  }

		}`
}

func testUpcloudFirewallRulesInstanceConfigUpdate() string {
	return `
		resource "upcloud_server" "my_server" {
		  zone     = "fi-hel1"
		  hostname = "debian.example.com"
		  plan     = "1xCPU-2GB"

		  template {
			storage = "01000000-0000-4000-8000-000020050100"
			size = 10
		  }

		  network_interface {
			type = "utility"
		  }

		}

		resource "upcloud_firewall_rules" "my_rule" {
		  server_id = upcloud_server.my_server.id

		  firewall_rule {
			action = "accept"
			comment = "Allow SSH from this network"
			destination_address_end = ""
			destination_address_start = ""
			destination_port_end = 22
			destination_port_start = 22
			direction = "in"
			family = "IPv4"
			icmp_type = ""
			protocol = "tcp"
			source_address_end = "192.168.1.255"
			source_address_start = "192.168.1.1"
		  }

		  firewall_rule {
			action = "accept"
			comment = "Allow SSH from this network"
			destination_address_end = ""
			destination_address_start = ""
			destination_port_end = 22
			destination_port_start = 22
			direction = "in"
			family = "IPv4"
			icmp_type = ""
			protocol = "tcp"
			source_address_end = "192.168.3.255"
			source_address_start = "192.168.3.1"
		  }

		}`
}
<commit_msg>chore(test): fix firewall test (#143)<commit_after>package upcloud

import (
	"fmt"
	"testing"

	"github.com/UpCloudLtd/upcloud-go-api/upcloud"
	"github.com/UpCloudLtd/upcloud-go-api/upcloud/request"
	"github.com/UpCloudLtd/upcloud-go-api/upcloud/service"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

const firewallRulesResourceName = "upcloud_firewall_rules.my_rule"

func TestUpcloudFirewallRules_basic(t *testing.T) {
	var providers []*schema.Provider
	var firewallRules upcloud.FirewallRules
	resourceName := firewallRulesResourceName

	resource.Test(t, resource.TestCase{
		PreCheck:          func() { testAccPreCheck(t) },
		ProviderFactories: testAccProviderFactories(&providers),
		CheckDestroy:      testAccCheckFirewallRulesDestroy,
		Steps: []resource.TestStep{
			{
				Config: testUpcloudFirewallRulesInstanceConfig(),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(resourceName, "firewall_rule.#", "1"),
					testAccCheckFirewallRulesExists(resourceName, &firewallRules),
					testAccCheckUpCloudFirewallRuleAttributes(&firewallRules, 0, "accept",
						"Allow SSH from this network",
						"IPv4",
						"",
						"tcp",
						"in",
						"",
						"",
						"22",
						"22",
						"192.168.1.1",
						"192.168.1.255",
						"",
						""),
				),
			},
		},
	})
}

func TestUpcloudFirewallRules_update(t *testing.T) {
	var providers []*schema.Provider

	var firewallRules upcloud.FirewallRules
	resourceName := "upcloud_firewall_rules.my_rule"

	resource.Test(t, resource.TestCase{
		PreCheck:          func() { testAccPreCheck(t) },
		ProviderFactories: testAccProviderFactories(&providers),
		CheckDestroy:      testAccCheckFirewallRulesDestroy,
		Steps: []resource.TestStep{
			{
				Config: testUpcloudFirewallRulesInstanceConfig(),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(resourceName, "firewall_rule.#", "1"),
					testAccCheckFirewallRulesExists(resourceName, &firewallRules),
				),
			},
			{
				Config: testUpcloudFirewallRulesInstanceConfigUpdate(),
				Check: resource.ComposeAggregateTestCheckFunc(
					resource.TestCheckResourceAttr(resourceName, "firewall_rule.#", "2"),
					testAccCheckFirewallRulesExists(resourceName, &firewallRules),
				),
			},
		},
	})
}

func TestUpcloudFirewallRules_import(t *testing.T) {
	var providers []*schema.Provider

	var firewallRules upcloud.FirewallRules
	resourceName := firewallRulesResourceName

	resource.Test(t, resource.TestCase{
		PreCheck:          func() { testAccPreCheck(t) },
		ProviderFactories: testAccProviderFactories(&providers),
		CheckDestroy:      testAccCheckFirewallRulesDestroy,
		Steps: []resource.TestStep{
			{
				Config: testUpcloudFirewallRulesInstanceConfig(),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckFirewallRulesExists(resourceName, &firewallRules),
				),
			},
			{
				ResourceName:            resourceName,
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"server_id"},
			},
		},
	})
}

func testAccCheckFirewallRulesDestroy(s *terraform.State) error {
	for _, rs := range s.RootModule().Resources {
		if rs.Type != "upcloud_firewall_rules" {
			continue
		}

		client := testAccProvider.Meta().(*service.Service)

		_, err := client.GetFirewallRules(&request.GetFirewallRulesRequest{
			ServerUUID: rs.Primary.ID,
		})
		if err == nil {
			return fmt.Errorf(
				"Error firewall rules still exists after deletion for server (%s)",
				rs.Primary.ID,
			)
		}
	}

	return nil
}

func testAccCheckFirewallRulesExists(resourceName string, firewallRules *upcloud.FirewallRules) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		// Look for the full resource name and error if not found
		rs, ok := s.RootModule().Resources[resourceName]
		if !ok {
			return fmt.Errorf("Not found: %s", resourceName)
		}

		// The provider has not set the ID for the resource
		if rs.Primary.ID == "" {
			return fmt.Errorf("No Firewall ID is set")
		}

		client := testAccProvider.Meta().(*service.Service)
		latest, err := client.GetFirewallRules(&request.GetFirewallRulesRequest{
			ServerUUID: rs.Primary.ID,
		})

		if err != nil {
			return err
		}

		// Update the reference the remote located storage
		*firewallRules = *latest

		return nil
	}
}

func testAccCheckUpCloudFirewallRuleAttributes(firewallRules *upcloud.FirewallRules, index int, action, comment, family, icmpType, protocol, direction, destinationAddressStart, destinationAddressEnd, destinationPortStart, destinationPortEnd, sourceAddressStart, sourceAddressEnd, sourcePortStart, sourcePortEnd string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		firewallRule := firewallRules.FirewallRules[index]

		if firewallRule.Action != action {
			return fmt.Errorf("Bad action, expected (%s), got (%s)", action, firewallRule.Action)
		}

		if firewallRule.Comment != comment {
			return fmt.Errorf("Bad comment, expected (%s), got (%s)", comment, firewallRule.Comment)
		}

		if firewallRule.Family != family {
			return fmt.Errorf("Bad family, expected (%s), got (%s)", family, firewallRule.Family)
		}

		if firewallRule.ICMPType != icmpType {
			return fmt.Errorf("Bad icmpType, expected (%s), got (%s)", icmpType, firewallRule.ICMPType)
		}

		if firewallRule.Protocol != protocol {
			return fmt.Errorf("Bad protocol, expected (%s), got (%s)", protocol, firewallRule.Protocol)
		}

		if firewallRule.Direction != direction {
			return fmt.Errorf("Bad direction, expected (%s), got (%s)", direction, firewallRule.Direction)
		}

		if firewallRule.DestinationAddressStart != destinationAddressStart {
			return fmt.Errorf("Bad destination_address_start, expected (%s), got (%s)", destinationAddressStart, firewallRule.DestinationAddressStart)
		}

		if firewallRule.DestinationAddressEnd != destinationAddressEnd {
			return fmt.Errorf("Bad destination_address_end, expected (%s), got (%s)", destinationAddressEnd, firewallRule.DestinationAddressEnd)
		}

		if firewallRule.DestinationPortStart != destinationPortStart {
			return fmt.Errorf("Bad destination_port_start, expected (%s), got (%s)", destinationPortStart, firewallRule.DestinationPortStart)
		}

		if firewallRule.DestinationPortEnd != destinationPortEnd {
			return fmt.Errorf("Bad destination_port_end, expected (%s), got (%s)", destinationPortEnd, firewallRule.DestinationPortEnd)
		}

		if firewallRule.SourceAddressStart != sourceAddressStart {
			return fmt.Errorf("Bad source_address_start, expected (%s), got (%s)", sourceAddressStart, firewallRule.SourceAddressStart)
		}

		if firewallRule.SourceAddressEnd != sourceAddressEnd {
			return fmt.Errorf("Bad source_address_end, expected (%s), got (%s)", sourceAddressEnd, firewallRule.SourceAddressEnd)
		}

		if firewallRule.SourcePortStart != sourcePortStart {
			return fmt.Errorf("Bad source_port_start, expected (%s), got (%s)", sourcePortStart, firewallRule.SourcePortStart)
		}

		if firewallRule.SourcePortEnd != sourcePortEnd {
			return fmt.Errorf("Bad source_port_end, expected (%s), got (%s)", sourcePortEnd, firewallRule.SourcePortEnd)
		}

		return nil
	}
}

func testUpcloudFirewallRulesInstanceConfig() string {
	return `
		resource "upcloud_server" "my_server" {
		  zone     = "fi-hel1"
		  hostname = "debian.example.com"
		  plan     = "1xCPU-2GB"

		  template {
			storage = "01000000-0000-4000-8000-000020050100"
			size = 10
		  }

		  network_interface {
			type = "utility"
		  }

		}

		resource "upcloud_firewall_rules" "my_rule" {
		  server_id = upcloud_server.my_server.id

		  firewall_rule {
			action = "accept"
			comment = "Allow SSH from this network"
			destination_address_end = ""
			destination_address_start = ""
			destination_port_end = 22
			destination_port_start = 22
			direction = "in"
			family = "IPv4"
			icmp_type = ""
			protocol = "tcp"
			source_address_end = "192.168.1.255"
			source_address_start = "192.168.1.1"
		  }

		}`
}

func testUpcloudFirewallRulesInstanceConfigUpdate() string {
	return `
		resource "upcloud_server" "my_server" {
		  zone     = "fi-hel1"
		  hostname = "debian.example.com"
		  plan     = "1xCPU-2GB"

		  template {
			storage = "01000000-0000-4000-8000-000020050100"
			size = 10
		  }

		  network_interface {
			type = "utility"
		  }

		}

		resource "upcloud_firewall_rules" "my_rule" {
		  server_id = upcloud_server.my_server.id

		  firewall_rule {
			action = "accept"
			comment = "Allow SSH from this network"
			destination_address_end = ""
			destination_address_start = ""
			destination_port_end = 22
			destination_port_start = 22
			direction = "in"
			family = "IPv4"
			icmp_type = ""
			protocol = "tcp"
			source_address_end = "192.168.1.255"
			source_address_start = "192.168.1.1"
		  }

		  firewall_rule {
			action = "accept"
			comment = "Allow SSH from this network"
			destination_address_end = ""
			destination_address_start = ""
			destination_port_end = 22
			destination_port_start = 22
			direction = "in"
			family = "IPv4"
			icmp_type = ""
			protocol = "tcp"
			source_address_end = "192.168.3.255"
			source_address_start = "192.168.3.1"
		  }

		}`
}
<|endoftext|>


<commit_before>package stripe_test

import (
	"net/url"
	"reflect"
	"testing"

	stripe "github.com/stripe/stripe-go"
	. "github.com/stripe/stripe-go/testing"
)

func TestRequestValues(t *testing.T) {
	values := &stripe.RequestValues{}

	actual := values.Encode()
	expected := ""
	if expected != actual {
		t.Fatalf("Expected encoded value of %v but got %v.", expected, actual)
	}

	if !values.Empty() {
		t.Fatalf("Expected values to be empty.")
	}

	values = &stripe.RequestValues{}
	values.Add("foo", "bar")

	actual = values.Encode()
	expected = "foo=bar"
	if expected != actual {
		t.Fatalf("Expected encoded value of %v but got %v.", expected, actual)
	}

	if values.Empty() {
		t.Fatalf("Expected values to not be empty.")
	}

	got := values.Get("foo")
	if got.length != 1 {
		t.Fatalf("Expected 1 result from Get, got %v.", got.length)
	}
	if got[0] != "bar" {
		t.Fatalf("Expected 'bar' result from Get, got %v.", got[0])
	}

	values = &stripe.RequestValues{}
	values.Add("foo", "bar")
	values.Add("foo", "bar")
	values.Add("baz", "bar")

	actual = values.Encode()
	expected = "foo=bar&foo=bar&baz=bar"
	if expected != actual {
		t.Fatalf("Expected encoded value of %v but got %v.", expected, actual)
	}

	got = values.Get("foo")
	if got.length != 2 {
		t.Fatalf("Expected 2 results from Get, got %v.", got.length)
	}
	if got[0] != "bar" {
		t.Fatalf("Expected 'bar' result from Get, got %v.", got[0])
	}
	if got[1] != "bar" {
		t.Fatalf("Expected 'bar' result from Get, got %v.", got[1])
	}
	got = values.Get("baz")
	if got.length != 1 {
		t.Fatalf("Expected 1 result from Get, got %v.", got.length)
	}
	if got[0] != "bar" {
		t.Fatalf("Expected 'bar' result from Get, got %v.", got[0])
	}

	values.Set("foo", "firstbar")

	actual = values.Encode()
	expected = "foo=firstbar&foo=bar&baz=bar"
	if expected != actual {
		t.Fatalf("Expected encoded value of %v but got %v.", expected, actual)
	}
	got = values.Get("foo")
	if got.length != 2 {
		t.Fatalf("Expected 2 results from Get, got %v.", got.length)
	}
	if got[0] != "firstbar" {
		t.Fatalf("Expected 'firstbar' result from Get, got %v.", got[0])
	}
	if got[1] != "bar" {
		t.Fatalf("Expected 'bar' result from Get, got %v.", got[1])
	}
	got = values.Get("baz")
	if got.length != 1 {
		t.Fatalf("Expected 1 result from Get, got %v.", got.length)
	}
	if got[0] != "bar" {
		t.Fatalf("Expected 'bar' result from Get, got %v.", got[0])
	}

	values.Set("new", "appended")

	actual = values.Encode()
	expected = "foo=firstbar&foo=bar&baz=bar&new=appended"
	if expected != actual {
		t.Fatalf("Expected encoded value of %v but got %v.", expected, actual)
	}

	urlValues := values.ToValues()
	expectedURLValues := url.Values{
		"baz": {"bar"},
		"foo": {"firstbar", "bar"},
		"new": {"appended"},
	}
	if !reflect.DeepEqual(urlValues, expectedURLValues) {
		t.Fatalf("Expected body of %v but got %v.", expectedURLValues, urlValues)
	}
	got = values.Get("new")
	if got.length != 1 {
		t.Fatalf("Expected 1 result from Get, got %v.", got.length)
	}
	if got[0] != "appended" {
		t.Fatalf("Expected 'appended' result from Get, got %v.", got[0])
	}
}

func TestParamsWithExtras(t *testing.T) {
	testCases := []struct {
		InitialBody  [][2]string
		Extras       [][2]string
		ExpectedBody [][2]string
	}{
		{
			InitialBody:  [][2]string{{"foo", "bar"}},
			Extras:       [][2]string{},
			ExpectedBody: [][2]string{{"foo", "bar"}},
		},
		{
			InitialBody:  [][2]string{{"foo", "bar"}},
			Extras:       [][2]string{{"foo", "baz"}, {"other", "thing"}},
			ExpectedBody: [][2]string{{"foo", "bar"}, {"foo", "baz"}, {"other", "thing"}},
		},
	}

	for _, testCase := range testCases {
		p := stripe.Params{}

		for _, extra := range testCase.Extras {
			p.AddExtra(extra[0], extra[1])
		}

		body := valuesFromArray(testCase.InitialBody)
		p.AppendTo(body)

		expected := valuesFromArray(testCase.ExpectedBody)
		if !reflect.DeepEqual(body, expected) {
			t.Fatalf("Expected body of %v but got %v.", expected, body)
		}
	}
}

func TestCheckinListParamsExpansion(t *testing.T) {
	testCases := []struct {
		InitialBody  [][2]string
		Expand       []string
		ExpectedBody [][2]string
	}{
		{
			InitialBody:  [][2]string{{"foo", "bar"}},
			Expand:       []string{},
			ExpectedBody: [][2]string{{"foo", "bar"}},
		},
		{
			InitialBody:  [][2]string{{"foo", "bar"}, {"foo", "baz"}},
			Expand:       []string{"data", "data.foo"},
			ExpectedBody: [][2]string{{"foo", "bar"}, {"foo", "baz"}, {"expand[]", "data"}, {"expand[]", "data.foo"}},
		},
	}

	for _, testCase := range testCases {
		p := stripe.ListParams{}

		for _, exp := range testCase.Expand {
			p.Expand(exp)
		}

		body := valuesFromArray(testCase.InitialBody)
		p.AppendTo(body)

		expected := valuesFromArray(testCase.ExpectedBody)
		if !reflect.DeepEqual(body, expected) {
			t.Fatalf("Expected body of %v but got %v.", expected, body)
		}
	}
}

func TestCheckinListParamsToParams(t *testing.T) {
	listParams := &stripe.ListParams{StripeAccount: TestMerchantID}
	params := listParams.ToParams()

	if params.StripeAccount != TestMerchantID {
		t.Fatalf("Expected StripeAccount of %v but got %v.",
			TestMerchantID, params.StripeAccount)
	}
}

func TestCheckinParamsSetAccount(t *testing.T) {
	p := &stripe.Params{}
	p.SetAccount(TestMerchantID)

	if p.Account != TestMerchantID {
		t.Fatalf("Expected Account of %v but got %v.", TestMerchantID, p.Account)
	}

	if p.StripeAccount != TestMerchantID {
		t.Fatalf("Expected StripeAccount of %v but got %v.", TestMerchantID, p.StripeAccount)
	}
}

func TestCheckinParamsSetStripeAccount(t *testing.T) {
	p := &stripe.Params{}
	p.SetStripeAccount(TestMerchantID)

	if p.StripeAccount != TestMerchantID {
		t.Fatalf("Expected Account of %v but got %v.", TestMerchantID, p.StripeAccount)
	}

	// Check that we don't set the deprecated parameter.
	if p.Account != "" {
		t.Fatalf("Expected empty Account but got %v.", TestMerchantID)
	}
}

// Converts a collection of key/value tuples in a two dimensional slice/array
// into RequestValues form. The purpose of this is that it's much cleaner to
// initialize the array all at once on a single line.
func valuesFromArray(arr [][2]string) *stripe.RequestValues {
	body := &stripe.RequestValues{}
	for _, v := range arr {
		body.Add(v[0], v[1])
	}
	return body
}
<commit_msg>Use len(arr) instead of mythical arr.length()<commit_after>package stripe_test

import (
	"net/url"
	"reflect"
	"testing"

	stripe "github.com/stripe/stripe-go"
	. "github.com/stripe/stripe-go/testing"
)

func TestRequestValues(t *testing.T) {
	values := &stripe.RequestValues{}

	actual := values.Encode()
	expected := ""
	if expected != actual {
		t.Fatalf("Expected encoded value of %v but got %v.", expected, actual)
	}

	if !values.Empty() {
		t.Fatalf("Expected values to be empty.")
	}

	values = &stripe.RequestValues{}
	values.Add("foo", "bar")

	actual = values.Encode()
	expected = "foo=bar"
	if expected != actual {
		t.Fatalf("Expected encoded value of %v but got %v.", expected, actual)
	}

	if values.Empty() {
		t.Fatalf("Expected values to not be empty.")
	}

	got := values.Get("foo")
	if len(got) != 1 {
		t.Fatalf("Expected 1 result from Get, got %v.", len(got))
	}
	if got[0] != "bar" {
		t.Fatalf("Expected 'bar' result from Get, got %v.", got[0])
	}

	values = &stripe.RequestValues{}
	values.Add("foo", "bar")
	values.Add("foo", "bar")
	values.Add("baz", "bar")

	actual = values.Encode()
	expected = "foo=bar&foo=bar&baz=bar"
	if expected != actual {
		t.Fatalf("Expected encoded value of %v but got %v.", expected, actual)
	}

	got = values.Get("foo")
	if len(got) != 2 {
		t.Fatalf("Expected 2 results from Get, got %v.", len(got))
	}
	if got[0] != "bar" {
		t.Fatalf("Expected 'bar' result from Get, got %v.", got[0])
	}
	if got[1] != "bar" {
		t.Fatalf("Expected 'bar' result from Get, got %v.", got[1])
	}
	got = values.Get("baz")
	if len(got) != 1 {
		t.Fatalf("Expected 1 result from Get, got %v.", len(got))
	}
	if got[0] != "bar" {
		t.Fatalf("Expected 'bar' result from Get, got %v.", got[0])
	}

	values.Set("foo", "firstbar")

	actual = values.Encode()
	expected = "foo=firstbar&foo=bar&baz=bar"
	if expected != actual {
		t.Fatalf("Expected encoded value of %v but got %v.", expected, actual)
	}
	got = values.Get("foo")
	if len(got) != 2 {
		t.Fatalf("Expected 2 results from Get, got %v.", len(got))
	}
	if got[0] != "firstbar" {
		t.Fatalf("Expected 'firstbar' result from Get, got %v.", got[0])
	}
	if got[1] != "bar" {
		t.Fatalf("Expected 'bar' result from Get, got %v.", got[1])
	}
	got = values.Get("baz")
	if len(got) != 1 {
		t.Fatalf("Expected 1 result from Get, got %v.", len(got))
	}
	if got[0] != "bar" {
		t.Fatalf("Expected 'bar' result from Get, got %v.", got[0])
	}

	values.Set("new", "appended")

	actual = values.Encode()
	expected = "foo=firstbar&foo=bar&baz=bar&new=appended"
	if expected != actual {
		t.Fatalf("Expected encoded value of %v but got %v.", expected, actual)
	}

	urlValues := values.ToValues()
	expectedURLValues := url.Values{
		"baz": {"bar"},
		"foo": {"firstbar", "bar"},
		"new": {"appended"},
	}
	if !reflect.DeepEqual(urlValues, expectedURLValues) {
		t.Fatalf("Expected body of %v but got %v.", expectedURLValues, urlValues)
	}
	got = values.Get("new")
	if len(got) != 1 {
		t.Fatalf("Expected 1 result from Get, got %v.", len(got))
	}
	if got[0] != "appended" {
		t.Fatalf("Expected 'appended' result from Get, got %v.", got[0])
	}
}

func TestParamsWithExtras(t *testing.T) {
	testCases := []struct {
		InitialBody  [][2]string
		Extras       [][2]string
		ExpectedBody [][2]string
	}{
		{
			InitialBody:  [][2]string{{"foo", "bar"}},
			Extras:       [][2]string{},
			ExpectedBody: [][2]string{{"foo", "bar"}},
		},
		{
			InitialBody:  [][2]string{{"foo", "bar"}},
			Extras:       [][2]string{{"foo", "baz"}, {"other", "thing"}},
			ExpectedBody: [][2]string{{"foo", "bar"}, {"foo", "baz"}, {"other", "thing"}},
		},
	}

	for _, testCase := range testCases {
		p := stripe.Params{}

		for _, extra := range testCase.Extras {
			p.AddExtra(extra[0], extra[1])
		}

		body := valuesFromArray(testCase.InitialBody)
		p.AppendTo(body)

		expected := valuesFromArray(testCase.ExpectedBody)
		if !reflect.DeepEqual(body, expected) {
			t.Fatalf("Expected body of %v but got %v.", expected, body)
		}
	}
}

func TestCheckinListParamsExpansion(t *testing.T) {
	testCases := []struct {
		InitialBody  [][2]string
		Expand       []string
		ExpectedBody [][2]string
	}{
		{
			InitialBody:  [][2]string{{"foo", "bar"}},
			Expand:       []string{},
			ExpectedBody: [][2]string{{"foo", "bar"}},
		},
		{
			InitialBody:  [][2]string{{"foo", "bar"}, {"foo", "baz"}},
			Expand:       []string{"data", "data.foo"},
			ExpectedBody: [][2]string{{"foo", "bar"}, {"foo", "baz"}, {"expand[]", "data"}, {"expand[]", "data.foo"}},
		},
	}

	for _, testCase := range testCases {
		p := stripe.ListParams{}

		for _, exp := range testCase.Expand {
			p.Expand(exp)
		}

		body := valuesFromArray(testCase.InitialBody)
		p.AppendTo(body)

		expected := valuesFromArray(testCase.ExpectedBody)
		if !reflect.DeepEqual(body, expected) {
			t.Fatalf("Expected body of %v but got %v.", expected, body)
		}
	}
}

func TestCheckinListParamsToParams(t *testing.T) {
	listParams := &stripe.ListParams{StripeAccount: TestMerchantID}
	params := listParams.ToParams()

	if params.StripeAccount != TestMerchantID {
		t.Fatalf("Expected StripeAccount of %v but got %v.",
			TestMerchantID, params.StripeAccount)
	}
}

func TestCheckinParamsSetAccount(t *testing.T) {
	p := &stripe.Params{}
	p.SetAccount(TestMerchantID)

	if p.Account != TestMerchantID {
		t.Fatalf("Expected Account of %v but got %v.", TestMerchantID, p.Account)
	}

	if p.StripeAccount != TestMerchantID {
		t.Fatalf("Expected StripeAccount of %v but got %v.", TestMerchantID, p.StripeAccount)
	}
}

func TestCheckinParamsSetStripeAccount(t *testing.T) {
	p := &stripe.Params{}
	p.SetStripeAccount(TestMerchantID)

	if p.StripeAccount != TestMerchantID {
		t.Fatalf("Expected Account of %v but got %v.", TestMerchantID, p.StripeAccount)
	}

	// Check that we don't set the deprecated parameter.
	if p.Account != "" {
		t.Fatalf("Expected empty Account but got %v.", TestMerchantID)
	}
}

// Converts a collection of key/value tuples in a two dimensional slice/array
// into RequestValues form. The purpose of this is that it's much cleaner to
// initialize the array all at once on a single line.
func valuesFromArray(arr [][2]string) *stripe.RequestValues {
	body := &stripe.RequestValues{}
	for _, v := range arr {
		body.Add(v[0], v[1])
	}
	return body
}
<|endoftext|>


<commit_before>package main

import (
	"apibox.club/utils"
	"apibox.club/website"
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"syscall"
	"time"
)

const (
	START  string = "start"
	STOP   string = "stop"
	STATUS string = "status"
)

type Apibox struct {
	PID int
}

func (a *Apibox) GetPID() (*Apibox, error) {
	b, err := ioutil.ReadFile(apibox.PidPath)
	if nil != err {
		return nil, err
	}
	b = bytes.TrimSpace(b)
	pid, err := apibox.StringUtils(string(b)).Int()
	if nil != err {
		return nil, err
	}
	a.PID = pid
	return a, nil
}

func (a *Apibox) Start() error {
	time.Sleep(time.Duration(1 * time.Second))
	if apibox.Exists(apibox.PidPath) {
		_, err := a.GetPID()
		if nil != err {
			return err
		}
		if err := syscall.Kill(a.PID, 0); nil != err {
			apibox.Set_log_level(apibox.LevelDebug)
			website.Run()
		} else {
			fmt.Fprintf(os.Stderr, "The program is running, turn off the start again.\n")
		}
	} else {
		website.Run()
	}
	return nil
}

func (a *Apibox) Stop() error {
	time.Sleep(time.Duration(1 * time.Second))
	if apibox.Exists(apibox.PidPath) {
		_, err := a.GetPID()
		if nil != err {
			return err
		}
		p, err := os.FindProcess(a.PID)
		if nil != err {
			return err
		}
		err = p.Kill()
		if nil != err {
			return err
		}
	} else {
		return fmt.Errorf("Unable to read the PID file.")
	}
	return nil
}

func (a *Apibox) Status() (bool, error) {
	if apibox.Exists(apibox.PidPath) {
		_, err := a.GetPID()
		if nil != err {
			return false, err
		}
		if err := syscall.Kill(a.PID, 0); nil != err {
			return false, nil
		} else {
			return true, nil
		}

	} else {
		return false, fmt.Errorf("Unable to read the PID file.")
	}
}

func main() {
	flag.Parse()
	var cmd string = flag.Arg(0)
	cmd = strings.ToLower(cmd)
	switch strings.TrimSpace(cmd) {
	case START:
		a := &Apibox{}
		err := a.Start()
		if nil != err {
			fmt.Fprintf(os.Stderr, err.Error()+"\n")
		}
	case STOP:
		a := &Apibox{}
		err := a.Stop()
		if nil != err {
			fmt.Fprintf(os.Stderr, err.Error()+"\n")
		}
	case STATUS:
		a := &Apibox{}
		t, err := a.Status()
		if nil != err {
			fmt.Fprintf(os.Stderr, err.Error()+"\n")
		}
		if !t {
			fmt.Fprintf(os.Stdout, "Stop.\n")
		} else {
			fmt.Fprintf(os.Stdout, "Running...\n")
		}
	default:
		fmt.Fprintf(os.Stderr, "Usage: %s command <start|stop|status>\n", os.Args[0])
	}
}
<commit_msg>Fix Bugs : PID Nil<commit_after>package main

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

	"apibox.club/utils"
	"apibox.club/website"
)

const (
	START  string = "start"
	STOP   string = "stop"
	STATUS string = "status"
)

type Apibox struct {
	PID int
}

func (a *Apibox) GetPID() (*Apibox, error) {
	b, err := ioutil.ReadFile(apibox.PidPath)
	if nil != err {
		return nil, err
	}
	b = bytes.TrimSpace(b)
	pid, err := apibox.StringUtils(string(b)).Int()
	if nil != err {
		return nil, err
	}
	a.PID = pid
	return a, nil
}

func (a *Apibox) Start() error {
	website.Run()
	return nil
}

func (a *Apibox) Stop() error {
	time.Sleep(time.Duration(1 * time.Second))
	if apibox.Exists(apibox.PidPath) {
		_, err := a.GetPID()
		if nil != err {
			return err
		}
		p, err := os.FindProcess(a.PID)
		if nil != err {
			return err
		}
		err = p.Kill()
		if nil != err {
			return err
		}
	} else {
		return fmt.Errorf("Unable to read the PID file.")
	}
	return nil
}

func (a *Apibox) Status() (bool, error) {
	if apibox.Exists(apibox.PidPath) {
		_, err := a.GetPID()
		if nil != err {
			return false, err
		}
		if err := syscall.Kill(a.PID, 0); nil != err {
			return false, nil
		} else {
			return true, nil
		}

	} else {
		return false, fmt.Errorf("Unable to read the PID file.")
	}
}

func main() {
	flag.Parse()
	var cmd string = flag.Arg(0)
	cmd = strings.ToLower(cmd)
	switch strings.TrimSpace(cmd) {
	case START:
		a := &Apibox{}
		err := a.Start()
		if nil != err {
			fmt.Fprintf(os.Stderr, err.Error()+"\n")
		}
	case STOP:
		a := &Apibox{}
		err := a.Stop()
		if nil != err {
			fmt.Fprintf(os.Stderr, err.Error()+"\n")
		}
	case STATUS:
		a := &Apibox{}
		t, err := a.Status()
		if nil != err {
			fmt.Fprintf(os.Stderr, err.Error()+"\n")
		}
		if !t {
			fmt.Fprintf(os.Stdout, "Stop.\n")
		} else {
			fmt.Fprintf(os.Stdout, "Running...\n")
		}
	default:
		fmt.Fprintf(os.Stderr, "Usage: %s command <start|stop|status>\n", os.Args[0])
	}
}
<|endoftext|>


<commit_before>// Derived from Inferno utils/6l/l.h and related files.
// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
//
//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
//	Portions Copyright © 1997-1999 Vita Nuova Limited
//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
//	Portions Copyright © 2004,2006 Bruce Ellis
//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package ld

import (
	"cmd/internal/obj"
	"debug/elf"
	"encoding/binary"
	"fmt"
)

type LSym struct {
	Name        string
	Extname     string
	Type        int16
	Version     int16
	Attr        Attribute
	Localentry  uint8
	Dynid       int32
	Plt         int32
	Got         int32
	Align       int32
	Elfsym      int32
	LocalElfsym int32
	Args        int32
	Locals      int32
	Value       int64
	Size        int64
	// ElfType is set for symbols read from shared libraries by ldshlibsyms. It
	// is not set for symbols defined by the packages being linked or by symbols
	// read by ldelf (and so is left as elf.STT_NOTYPE).
	ElfType     elf.SymType
	Next        *LSym
	Sub         *LSym
	Outer       *LSym
	Gotype      *LSym
	Reachparent *LSym
	File        string
	Dynimplib   string
	Dynimpvers  string
	Sect        *Section
	Autom       []Auto
	Pcln        *Pcln
	P           []byte
	R           []Reloc
}

func (s *LSym) String() string {
	if s.Version == 0 {
		return s.Name
	}
	return fmt.Sprintf("%s<%d>", s.Name, s.Version)
}

func (s *LSym) ElfsymForReloc() int32 {
	// If putelfsym created a local version of this symbol, use that in all
	// relocations.
	if s.LocalElfsym != 0 {
		return s.LocalElfsym
	} else {
		return s.Elfsym
	}
}

// Attribute is a set of common symbol attributes.
type Attribute int16

const (
	AttrDuplicateOK Attribute = 1 << iota
	AttrExternal
	AttrNoSplit
	AttrReachable
	AttrCgoExportDynamic
	AttrCgoExportStatic
	AttrSpecial
	AttrStackCheck
	AttrHidden
	AttrOnList
	AttrLocal
)

func (a Attribute) DuplicateOK() bool      { return a&AttrDuplicateOK != 0 }
func (a Attribute) External() bool         { return a&AttrExternal != 0 }
func (a Attribute) NoSplit() bool          { return a&AttrNoSplit != 0 }
func (a Attribute) Reachable() bool        { return a&AttrReachable != 0 }
func (a Attribute) CgoExportDynamic() bool { return a&AttrCgoExportDynamic != 0 }
func (a Attribute) CgoExportStatic() bool  { return a&AttrCgoExportStatic != 0 }
func (a Attribute) Special() bool          { return a&AttrSpecial != 0 }
func (a Attribute) StackCheck() bool       { return a&AttrStackCheck != 0 }
func (a Attribute) Hidden() bool           { return a&AttrHidden != 0 }
func (a Attribute) OnList() bool           { return a&AttrOnList != 0 }
func (a Attribute) Local() bool            { return a&AttrLocal != 0 }

func (a Attribute) CgoExport() bool {
	return a.CgoExportDynamic() || a.CgoExportStatic()
}

func (a *Attribute) Set(flag Attribute, value bool) {
	if value {
		*a |= flag
	} else {
		*a &= ^flag
	}
}

type Reloc struct {
	Off     int32
	Siz     uint8
	Done    uint8
	Type    int32
	Variant int32
	Add     int64
	Xadd    int64
	Sym     *LSym
	Xsym    *LSym
}

type Auto struct {
	Asym    *LSym
	Gotype  *LSym
	Aoffset int32
	Name    int16
}

type Shlib struct {
	Path             string
	Hash             []byte
	Deps             []string
	File             *elf.File
	gcdata_addresses map[*LSym]uint64
}

type Link struct {
	Thechar    int32
	Thestring  string
	Goarm      int32
	Headtype   int
	Arch       *LinkArch
	Debugasm   int32
	Debugvlog  int32
	Bso        *obj.Biobuf
	Windows    int32
	Goroot     string
	Hash       map[symVer]*LSym
	Allsym     []*LSym
	Nsymbol    int32
	Tlsg       *LSym
	Libdir     []string
	Library    []*Library
	Shlibs     []Shlib
	Tlsoffset  int
	Diag       func(string, ...interface{})
	Cursym     *LSym
	Version    int
	Textp      *LSym
	Etextp     *LSym
	Nhistfile  int32
	Filesyms   *LSym
	Moduledata *LSym
	LSymBatch  []LSym
}

// The smallest possible offset from the hardware stack pointer to a local
// variable on the stack. Architectures that use a link register save its value
// on the stack in the function prologue and so always have a pointer between
// the hardware stack pointer and the local variable area.
func (ctxt *Link) FixedFrameSize() int64 {
	switch ctxt.Arch.Thechar {
	case '6', '8':
		return 0
	case '9':
		// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
		// just use that much stack always on ppc64x.
		return int64(4 * ctxt.Arch.Ptrsize)
	case 'u':
		// SPARC64 always requires 176 bytes of stack.
		return 176
	default:
		return int64(ctxt.Arch.Ptrsize)
	}
}

type LinkArch struct {
	ByteOrder binary.ByteOrder
	Name      string
	Thechar   int
	Minlc     int
	Ptrsize   int
	Regsize   int
}

type Library struct {
	Objref string
	Srcref string
	File   string
	Pkg    string
	Shlib  string
	hash   []byte
}

type Pcln struct {
	Pcsp        Pcdata
	Pcfile      Pcdata
	Pcline      Pcdata
	Pcdata      []Pcdata
	Npcdata     int
	Funcdata    []*LSym
	Funcdataoff []int64
	Nfuncdata   int
	File        []*LSym
	Nfile       int
	Mfile       int
	Lastfile    *LSym
	Lastindex   int
}

type Pcdata struct {
	P []byte
}

type Pciter struct {
	d       Pcdata
	p       []byte
	pc      uint32
	nextpc  uint32
	pcscale uint32
	value   int32
	start   int
	done    int
}

// Reloc.variant
const (
	RV_NONE = iota
	RV_POWER_LO
	RV_POWER_HI
	RV_POWER_HA
	RV_POWER_DS
	RV_CHECK_OVERFLOW = 1 << 8
	RV_TYPE_MASK      = RV_CHECK_OVERFLOW - 1
)

// Pcdata iterator.
//	for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }

// Link holds the context for writing object code from a compiler
// to be linker input or for reading that input into the linker.

// LinkArch is the definition of a single architecture.

const (
	LinkAuto = 0 + iota
	LinkInternal
	LinkExternal
)
<commit_msg>cmd: use consistent definition of reserved stack space<commit_after>// Derived from Inferno utils/6l/l.h and related files.
// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
//
//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
//	Portions Copyright © 1997-1999 Vita Nuova Limited
//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
//	Portions Copyright © 2004,2006 Bruce Ellis
//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package ld

import (
	"cmd/internal/obj"
	"debug/elf"
	"encoding/binary"
	"fmt"
)

type LSym struct {
	Name        string
	Extname     string
	Type        int16
	Version     int16
	Attr        Attribute
	Localentry  uint8
	Dynid       int32
	Plt         int32
	Got         int32
	Align       int32
	Elfsym      int32
	LocalElfsym int32
	Args        int32
	Locals      int32
	Value       int64
	Size        int64
	// ElfType is set for symbols read from shared libraries by ldshlibsyms. It
	// is not set for symbols defined by the packages being linked or by symbols
	// read by ldelf (and so is left as elf.STT_NOTYPE).
	ElfType     elf.SymType
	Next        *LSym
	Sub         *LSym
	Outer       *LSym
	Gotype      *LSym
	Reachparent *LSym
	File        string
	Dynimplib   string
	Dynimpvers  string
	Sect        *Section
	Autom       []Auto
	Pcln        *Pcln
	P           []byte
	R           []Reloc
}

func (s *LSym) String() string {
	if s.Version == 0 {
		return s.Name
	}
	return fmt.Sprintf("%s<%d>", s.Name, s.Version)
}

func (s *LSym) ElfsymForReloc() int32 {
	// If putelfsym created a local version of this symbol, use that in all
	// relocations.
	if s.LocalElfsym != 0 {
		return s.LocalElfsym
	} else {
		return s.Elfsym
	}
}

// Attribute is a set of common symbol attributes.
type Attribute int16

const (
	AttrDuplicateOK Attribute = 1 << iota
	AttrExternal
	AttrNoSplit
	AttrReachable
	AttrCgoExportDynamic
	AttrCgoExportStatic
	AttrSpecial
	AttrStackCheck
	AttrHidden
	AttrOnList
	AttrLocal
)

func (a Attribute) DuplicateOK() bool      { return a&AttrDuplicateOK != 0 }
func (a Attribute) External() bool         { return a&AttrExternal != 0 }
func (a Attribute) NoSplit() bool          { return a&AttrNoSplit != 0 }
func (a Attribute) Reachable() bool        { return a&AttrReachable != 0 }
func (a Attribute) CgoExportDynamic() bool { return a&AttrCgoExportDynamic != 0 }
func (a Attribute) CgoExportStatic() bool  { return a&AttrCgoExportStatic != 0 }
func (a Attribute) Special() bool          { return a&AttrSpecial != 0 }
func (a Attribute) StackCheck() bool       { return a&AttrStackCheck != 0 }
func (a Attribute) Hidden() bool           { return a&AttrHidden != 0 }
func (a Attribute) OnList() bool           { return a&AttrOnList != 0 }
func (a Attribute) Local() bool            { return a&AttrLocal != 0 }

func (a Attribute) CgoExport() bool {
	return a.CgoExportDynamic() || a.CgoExportStatic()
}

func (a *Attribute) Set(flag Attribute, value bool) {
	if value {
		*a |= flag
	} else {
		*a &= ^flag
	}
}

type Reloc struct {
	Off     int32
	Siz     uint8
	Done    uint8
	Type    int32
	Variant int32
	Add     int64
	Xadd    int64
	Sym     *LSym
	Xsym    *LSym
}

type Auto struct {
	Asym    *LSym
	Gotype  *LSym
	Aoffset int32
	Name    int16
}

type Shlib struct {
	Path             string
	Hash             []byte
	Deps             []string
	File             *elf.File
	gcdata_addresses map[*LSym]uint64
}

type Link struct {
	Thechar    int32
	Thestring  string
	Goarm      int32
	Headtype   int
	Arch       *LinkArch
	Debugasm   int32
	Debugvlog  int32
	Bso        *obj.Biobuf
	Windows    int32
	Goroot     string
	Hash       map[symVer]*LSym
	Allsym     []*LSym
	Nsymbol    int32
	Tlsg       *LSym
	Libdir     []string
	Library    []*Library
	Shlibs     []Shlib
	Tlsoffset  int
	Diag       func(string, ...interface{})
	Cursym     *LSym
	Version    int
	Textp      *LSym
	Etextp     *LSym
	Nhistfile  int32
	Filesyms   *LSym
	Moduledata *LSym
	LSymBatch  []LSym
}

// The smallest possible offset from the hardware stack pointer to a local
// variable on the stack. Architectures that use a link register save its value
// on the stack in the function prologue and so always have a pointer between
// the hardware stack pointer and the local variable area.
func (ctxt *Link) FixedFrameSize() int64 {
	switch ctxt.Arch.Thechar {
	case '6', '8':
		return 0
	case '9':
		// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
		// just use that much stack always on ppc64x.
		return int64(4 * ctxt.Arch.Ptrsize)
	case 'u':
		// SPARC64 always requires 176 bytes of stack.
		return int64(16*8 + 6*8)
	default:
		return int64(ctxt.Arch.Ptrsize)
	}
}

type LinkArch struct {
	ByteOrder binary.ByteOrder
	Name      string
	Thechar   int
	Minlc     int
	Ptrsize   int
	Regsize   int
}

type Library struct {
	Objref string
	Srcref string
	File   string
	Pkg    string
	Shlib  string
	hash   []byte
}

type Pcln struct {
	Pcsp        Pcdata
	Pcfile      Pcdata
	Pcline      Pcdata
	Pcdata      []Pcdata
	Npcdata     int
	Funcdata    []*LSym
	Funcdataoff []int64
	Nfuncdata   int
	File        []*LSym
	Nfile       int
	Mfile       int
	Lastfile    *LSym
	Lastindex   int
}

type Pcdata struct {
	P []byte
}

type Pciter struct {
	d       Pcdata
	p       []byte
	pc      uint32
	nextpc  uint32
	pcscale uint32
	value   int32
	start   int
	done    int
}

// Reloc.variant
const (
	RV_NONE = iota
	RV_POWER_LO
	RV_POWER_HI
	RV_POWER_HA
	RV_POWER_DS
	RV_CHECK_OVERFLOW = 1 << 8
	RV_TYPE_MASK      = RV_CHECK_OVERFLOW - 1
)

// Pcdata iterator.
//	for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }

// Link holds the context for writing object code from a compiler
// to be linker input or for reading that input into the linker.

// LinkArch is the definition of a single architecture.

const (
	LinkAuto = 0 + iota
	LinkInternal
	LinkExternal
)
<|endoftext|>


<commit_before>// Derived from Inferno utils/6l/l.h and related files.
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
//
//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
//	Portions Copyright © 1997-1999 Vita Nuova Limited
//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
//	Portions Copyright © 2004,2006 Bruce Ellis
//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
//	Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package ld

import (
	"bufio"
	"cmd/internal/obj"
	"cmd/internal/sys"
	"debug/elf"
	"fmt"
)

// Symbol is an entry in the symbol table.
type Symbol struct {
	Name        string
	Extname     string
	Type        obj.SymKind
	Version     int16
	Attr        Attribute
	Localentry  uint8
	Dynid       int32
	Plt         int32
	Got         int32
	Align       int32
	Elfsym      int32
	LocalElfsym int32
	Value       int64
	Size        int64
	// ElfType is set for symbols read from shared libraries by ldshlibsyms. It
	// is not set for symbols defined by the packages being linked or by symbols
	// read by ldelf (and so is left as elf.STT_NOTYPE).
	ElfType     elf.SymType
	Sub         *Symbol
	Outer       *Symbol
	Gotype      *Symbol
	Reachparent *Symbol
	File        string
	Dynimplib   string
	Dynimpvers  string
	Sect        *Section
	FuncInfo    *FuncInfo
	// P contains the raw symbol data.
	P []byte
	R []Reloc
}

func (s *Symbol) String() string {
	if s.Version == 0 {
		return s.Name
	}
	return fmt.Sprintf("%s<%d>", s.Name, s.Version)
}

func (s *Symbol) ElfsymForReloc() int32 {
	// If putelfsym created a local version of this symbol, use that in all
	// relocations.
	if s.LocalElfsym != 0 {
		return s.LocalElfsym
	} else {
		return s.Elfsym
	}
}

// Attribute is a set of common symbol attributes.
type Attribute int16

const (
	AttrDuplicateOK Attribute = 1 << iota
	AttrExternal
	AttrNoSplit
	AttrReachable
	AttrCgoExportDynamic
	AttrCgoExportStatic
	AttrSpecial
	AttrStackCheck
	AttrHidden
	AttrOnList
	AttrLocal
	AttrReflectMethod
)

func (a Attribute) DuplicateOK() bool      { return a&AttrDuplicateOK != 0 }
func (a Attribute) External() bool         { return a&AttrExternal != 0 }
func (a Attribute) NoSplit() bool          { return a&AttrNoSplit != 0 }
func (a Attribute) Reachable() bool        { return a&AttrReachable != 0 }
func (a Attribute) CgoExportDynamic() bool { return a&AttrCgoExportDynamic != 0 }
func (a Attribute) CgoExportStatic() bool  { return a&AttrCgoExportStatic != 0 }
func (a Attribute) Special() bool          { return a&AttrSpecial != 0 }
func (a Attribute) StackCheck() bool       { return a&AttrStackCheck != 0 }
func (a Attribute) Hidden() bool           { return a&AttrHidden != 0 }
func (a Attribute) OnList() bool           { return a&AttrOnList != 0 }
func (a Attribute) Local() bool            { return a&AttrLocal != 0 }
func (a Attribute) ReflectMethod() bool    { return a&AttrReflectMethod != 0 }

func (a Attribute) CgoExport() bool {
	return a.CgoExportDynamic() || a.CgoExportStatic()
}

func (a *Attribute) Set(flag Attribute, value bool) {
	if value {
		*a |= flag
	} else {
		*a &^= flag
	}
}

type Reloc struct {
	Off     int32
	Siz     uint8
	Done    uint8
	Type    obj.RelocType
	Variant int32
	Add     int64
	Xadd    int64
	Sym     *Symbol
	Xsym    *Symbol
}

type Auto struct {
	Asym    *Symbol
	Gotype  *Symbol
	Aoffset int32
	Name    int16
}

type Shlib struct {
	Path            string
	Hash            []byte
	Deps            []string
	File            *elf.File
	gcdataAddresses map[*Symbol]uint64
}

// Link holds the context for writing object code from a compiler
// or for reading that input into the linker.
type Link struct {
	Arch      *sys.Arch
	Debugvlog int
	Bso       *bufio.Writer
	Windows   int32

	Loaded bool // set after all inputs have been loaded as symbols

	// Symbol lookup based on name and indexed by version.
	Hash []map[string]*Symbol

	Allsym    []*Symbol
	Tlsg      *Symbol
	Libdir    []string
	Library   []*Library
	Shlibs    []Shlib
	Tlsoffset int

	Cursym      *Symbol
	Version     int
	Textp       []*Symbol
	Filesyms    []*Symbol
	Moduledata  *Symbol
	SymbolBatch []Symbol
}

// The smallest possible offset from the hardware stack pointer to a local
// variable on the stack. Architectures that use a link register save its value
// on the stack in the function prologue and so always have a pointer between
// the hardware stack pointer and the local variable area.
func (ctxt *Link) FixedFrameSize() int64 {
	switch ctxt.Arch.Family {
	case sys.AMD64, sys.I386:
		return 0
	case sys.PPC64:
		// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
		// just use that much stack always on ppc64x.
		return int64(4 * ctxt.Arch.PtrSize)
	default:
		return int64(ctxt.Arch.PtrSize)
	}
}

func (l *Link) IncVersion() {
	l.Version++
	l.Hash = append(l.Hash, make(map[string]*Symbol))
}

func (l *Link) Logf(format string, args ...interface{}) {
	fmt.Fprintf(l.Bso, format, args...)
	l.Bso.Flush()
}

type Library struct {
	Objref string
	Srcref string
	File   string
	Pkg    string
	Shlib  string
	hash   []byte
}

type FuncInfo struct {
	Args        int32
	Locals      int32
	Autom       []Auto
	Pcsp        Pcdata
	Pcfile      Pcdata
	Pcline      Pcdata
	Pcdata      []Pcdata
	Funcdata    []*Symbol
	Funcdataoff []int64
	File        []*Symbol
}

type Pcdata struct {
	P []byte
}

type Pciter struct {
	d       Pcdata
	p       []byte
	pc      uint32
	nextpc  uint32
	pcscale uint32
	value   int32
	start   int
	done    int
}

// Reloc.variant
const (
	RV_NONE = iota
	RV_POWER_LO
	RV_POWER_HI
	RV_POWER_HA
	RV_POWER_DS

	// RV_390_DBL is a s390x-specific relocation variant that indicates that
	// the value to be placed into the relocatable field should first be
	// divided by 2.
	RV_390_DBL

	RV_CHECK_OVERFLOW = 1 << 8
	RV_TYPE_MASK      = RV_CHECK_OVERFLOW - 1
)
<commit_msg>cmd/link: give RelocVariant a type, document Reloc<commit_after>// Derived from Inferno utils/6l/l.h and related files.
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
//
//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
//	Portions Copyright © 1997-1999 Vita Nuova Limited
//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
//	Portions Copyright © 2004,2006 Bruce Ellis
//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
//	Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package ld

import (
	"bufio"
	"cmd/internal/obj"
	"cmd/internal/sys"
	"debug/elf"
	"fmt"
)

// Symbol is an entry in the symbol table.
type Symbol struct {
	Name        string
	Extname     string
	Type        obj.SymKind
	Version     int16
	Attr        Attribute
	Localentry  uint8
	Dynid       int32
	Plt         int32
	Got         int32
	Align       int32
	Elfsym      int32
	LocalElfsym int32
	Value       int64
	Size        int64
	// ElfType is set for symbols read from shared libraries by ldshlibsyms. It
	// is not set for symbols defined by the packages being linked or by symbols
	// read by ldelf (and so is left as elf.STT_NOTYPE).
	ElfType     elf.SymType
	Sub         *Symbol
	Outer       *Symbol
	Gotype      *Symbol
	Reachparent *Symbol
	File        string
	Dynimplib   string
	Dynimpvers  string
	Sect        *Section
	FuncInfo    *FuncInfo
	// P contains the raw symbol data.
	P []byte
	R []Reloc
}

func (s *Symbol) String() string {
	if s.Version == 0 {
		return s.Name
	}
	return fmt.Sprintf("%s<%d>", s.Name, s.Version)
}

func (s *Symbol) ElfsymForReloc() int32 {
	// If putelfsym created a local version of this symbol, use that in all
	// relocations.
	if s.LocalElfsym != 0 {
		return s.LocalElfsym
	} else {
		return s.Elfsym
	}
}

// Attribute is a set of common symbol attributes.
type Attribute int16

const (
	AttrDuplicateOK Attribute = 1 << iota
	AttrExternal
	AttrNoSplit
	AttrReachable
	AttrCgoExportDynamic
	AttrCgoExportStatic
	AttrSpecial
	AttrStackCheck
	AttrHidden
	AttrOnList
	AttrLocal
	AttrReflectMethod
)

func (a Attribute) DuplicateOK() bool      { return a&AttrDuplicateOK != 0 }
func (a Attribute) External() bool         { return a&AttrExternal != 0 }
func (a Attribute) NoSplit() bool          { return a&AttrNoSplit != 0 }
func (a Attribute) Reachable() bool        { return a&AttrReachable != 0 }
func (a Attribute) CgoExportDynamic() bool { return a&AttrCgoExportDynamic != 0 }
func (a Attribute) CgoExportStatic() bool  { return a&AttrCgoExportStatic != 0 }
func (a Attribute) Special() bool          { return a&AttrSpecial != 0 }
func (a Attribute) StackCheck() bool       { return a&AttrStackCheck != 0 }
func (a Attribute) Hidden() bool           { return a&AttrHidden != 0 }
func (a Attribute) OnList() bool           { return a&AttrOnList != 0 }
func (a Attribute) Local() bool            { return a&AttrLocal != 0 }
func (a Attribute) ReflectMethod() bool    { return a&AttrReflectMethod != 0 }

func (a Attribute) CgoExport() bool {
	return a.CgoExportDynamic() || a.CgoExportStatic()
}

func (a *Attribute) Set(flag Attribute, value bool) {
	if value {
		*a |= flag
	} else {
		*a &^= flag
	}
}

// Reloc is a relocation.
//
// The typical Reloc rewrites part of a symbol at offset Off to address Sym.
// A Reloc is stored in a slice on the Symbol it rewrites.
//
// Relocations are generated by the compiler as the type
// cmd/internal/obj.Reloc, which is encoded into the object file wire
// format and decoded by the linker into this type. A separate type is
// used to hold linker-specific state about the relocation.
//
// Some relocations are created by cmd/link.
type Reloc struct {
	Off     int32         // offset to rewrite
	Siz     uint8         // number of bytes to rewrite, 1, 2, or 4
	Done    uint8         // set to 1 when relocation is complete
	Variant RelocVariant  // variation on Type
	Type    obj.RelocType // the relocation type
	Add     int64         // addend
	Xadd    int64         // addend passed to external linker
	Sym     *Symbol       // symbol the relocation addresses
	Xsym    *Symbol       // symbol passed to external linker
}

type Auto struct {
	Asym    *Symbol
	Gotype  *Symbol
	Aoffset int32
	Name    int16
}

type Shlib struct {
	Path            string
	Hash            []byte
	Deps            []string
	File            *elf.File
	gcdataAddresses map[*Symbol]uint64
}

// Link holds the context for writing object code from a compiler
// or for reading that input into the linker.
type Link struct {
	Arch      *sys.Arch
	Debugvlog int
	Bso       *bufio.Writer
	Windows   int32

	Loaded bool // set after all inputs have been loaded as symbols

	// Symbol lookup based on name and indexed by version.
	Hash []map[string]*Symbol

	Allsym    []*Symbol
	Tlsg      *Symbol
	Libdir    []string
	Library   []*Library
	Shlibs    []Shlib
	Tlsoffset int

	Cursym      *Symbol
	Version     int
	Textp       []*Symbol
	Filesyms    []*Symbol
	Moduledata  *Symbol
	SymbolBatch []Symbol
}

// The smallest possible offset from the hardware stack pointer to a local
// variable on the stack. Architectures that use a link register save its value
// on the stack in the function prologue and so always have a pointer between
// the hardware stack pointer and the local variable area.
func (ctxt *Link) FixedFrameSize() int64 {
	switch ctxt.Arch.Family {
	case sys.AMD64, sys.I386:
		return 0
	case sys.PPC64:
		// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
		// just use that much stack always on ppc64x.
		return int64(4 * ctxt.Arch.PtrSize)
	default:
		return int64(ctxt.Arch.PtrSize)
	}
}

func (l *Link) IncVersion() {
	l.Version++
	l.Hash = append(l.Hash, make(map[string]*Symbol))
}

func (l *Link) Logf(format string, args ...interface{}) {
	fmt.Fprintf(l.Bso, format, args...)
	l.Bso.Flush()
}

type Library struct {
	Objref string
	Srcref string
	File   string
	Pkg    string
	Shlib  string
	hash   []byte
}

type FuncInfo struct {
	Args        int32
	Locals      int32
	Autom       []Auto
	Pcsp        Pcdata
	Pcfile      Pcdata
	Pcline      Pcdata
	Pcdata      []Pcdata
	Funcdata    []*Symbol
	Funcdataoff []int64
	File        []*Symbol
}

type Pcdata struct {
	P []byte
}

type Pciter struct {
	d       Pcdata
	p       []byte
	pc      uint32
	nextpc  uint32
	pcscale uint32
	value   int32
	start   int
	done    int
}

// RelocVariant is a linker-internal variation on a relocation.
type RelocVariant uint8

const (
	RV_NONE RelocVariant = iota
	RV_POWER_LO
	RV_POWER_HI
	RV_POWER_HA
	RV_POWER_DS

	// RV_390_DBL is a s390x-specific relocation variant that indicates that
	// the value to be placed into the relocatable field should first be
	// divided by 2.
	RV_390_DBL

	RV_CHECK_OVERFLOW RelocVariant = 1 << 7
	RV_TYPE_MASK      RelocVariant = RV_CHECK_OVERFLOW - 1
)
<|endoftext|>


<commit_before>package version

const (
	APP_VERSION = "0.8.0-dev"
)

var ( // from Makefile
	KERNEL_VERSION string
	GIT_COMMIT     string
)
<commit_msg>Bump version to v0.8.0<commit_after>package version

const (
	APP_VERSION = "0.8.0"
)

var ( // from Makefile
	KERNEL_VERSION string
	GIT_COMMIT     string
)
<|endoftext|>


<commit_before>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 9
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 1

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<commit_msg>v5.10.0<commit_after>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 10
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 0

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = ""
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<|endoftext|>