<commit_before>package main

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"time"

	"github.com/kbrebanov/nose-bleed/parser"

	"github.com/google/gopacket"
	"github.com/google/gopacket/pcap"
	"github.com/streadway/amqp"
)

const version string = "0.4.0"

// RabbitMQPublishSettings is a structure for RabbitMQ publish settings
type RabbitMQPublishSettings struct {
	Key        string `json:"key"`
	Mandatory  bool   `json:"mandatory"`
	Immediate  bool   `json:"immediate"`
	Persistent bool   `json:"persistent"`
}

// RabbitMQExchangeSettings is a structure for RabbitMQ exchange settings
type RabbitMQExchangeSettings struct {
	Name       string `json:"name"`
	Type       string `json:"type"`
	Durable    bool   `json:"durable"`
	AutoDelete bool   `json:"auto_delete"`
	Internal   bool   `json:"internal"`
	NoWait     bool   `json:"no_wait"`
}

// RabbitMQTLSSettings is a structure for RabbitMQ TLS settings
type RabbitMQTLSSettings struct {
	Enabled    bool   `json:"enabled"`
	CACertFile string `json:"ca_cert_file"`
	CertFile   string `json:"cert_file"`
	KeyFile    string `json:"key_file"`
}

// RabbitMQSettings is a structure for RabbitMQ settings
type RabbitMQSettings struct {
	User     string                   `json:"user"`
	Password string                   `json:"password"`
	Host     string                   `json:"host"`
	Port     int                      `json:"port"`
	VHost    string                   `json:"vhost"`
	TLS      RabbitMQTLSSettings      `json:"tls"`
	Exchange RabbitMQExchangeSettings `json:"exchange"`
	Publish  RabbitMQPublishSettings  `json:"publish"`
}

// Settings is a structure for configuration settings
type Settings struct {
	RabbitMQ RabbitMQSettings `json:"rabbitmq,omitempty"`
}

// RabbitMQ error handler
func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

// sniff starts a live capture of network packets, parses and outputs
// the JSON results to either standard output or a RabbitMQ exchange.
func sniff(deviceName string, snapshotLen int, promiscuous bool, timeout time.Duration,
	filter string, settings *Settings) {

	var ch *amqp.Channel
	var conn *amqp.Connection
	var vhost string

	useRabbitMQ := false

	if settings.RabbitMQ.User != "" && settings.RabbitMQ.Password != "" && settings.RabbitMQ.Host != "" &&
		settings.RabbitMQ.Exchange.Name != "" && settings.RabbitMQ.Exchange.Type != "" {
		useRabbitMQ = true
	}

	if settings.RabbitMQ.VHost == "" {
		vhost = "/"
	} else {
		vhost = "/" + settings.RabbitMQ.VHost
	}

	// Initialize msg queue
	if useRabbitMQ {
		if settings.RabbitMQ.TLS.Enabled {
			tlsConfig := new(tls.Config)
			tlsConfig.RootCAs = x509.NewCertPool()

			if ca, err := ioutil.ReadFile(settings.RabbitMQ.TLS.CACertFile); err == nil {
				tlsConfig.RootCAs.AppendCertsFromPEM(ca)
			}

			if cert, err := tls.LoadX509KeyPair(settings.RabbitMQ.TLS.CertFile, settings.RabbitMQ.TLS.KeyFile); err == nil {
				tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
			}

			var err error
			conn, err = amqp.DialTLS(
				fmt.Sprintf("amqps://%s:%s@%s%s",
					settings.RabbitMQ.User,
					settings.RabbitMQ.Password,
					fmt.Sprintf("%s:%d", settings.RabbitMQ.Host, settings.RabbitMQ.Port),
					vhost),
				tlsConfig)
			failOnError(err, "Failed to connect to RabbitMQ using TLS")
			defer conn.Close()
		} else {
			var err error
			conn, err = amqp.Dial(
				fmt.Sprintf("amqp://%s:%s@%s%s",
					settings.RabbitMQ.User,
					settings.RabbitMQ.Password,
					fmt.Sprintf("%s:%d", settings.RabbitMQ.Host, settings.RabbitMQ.Port),
					vhost))
			failOnError(err, "Failed to connect to RabbitMQ")
			defer conn.Close()
		}

		var err error

		// Create a channel
		ch, err = conn.Channel()
		failOnError(err, "Failed to open a channel")
		defer ch.Close()

		// Declare an exchange
		err = ch.ExchangeDeclare(
			settings.RabbitMQ.Exchange.Name,
			settings.RabbitMQ.Exchange.Type,
			settings.RabbitMQ.Exchange.Durable,
			settings.RabbitMQ.Exchange.AutoDelete,
			settings.RabbitMQ.Exchange.Internal,
			settings.RabbitMQ.Exchange.NoWait,
			nil)
		failOnError(err, "Failed to declare an exchange")
	}

	// Start a live capture
	handle, err := pcap.OpenLive(deviceName, int32(snapshotLen), promiscuous, timeout)
	if err != nil {
		log.Fatalln("Failed to start packet capture:", err)
	}
	defer handle.Close()

	// Set filter
	if filter != "" {
		err = handle.SetBPFFilter(filter)
		if err != nil {
			log.Println("Failed to set BPF:", err)
		}
	}

	// Parse each packet
	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
	for packet := range packetSource.Packets() {
		headers, err := parser.Parse(packet)
		if err != nil {
			log.Println("Failed to parse packet:", err, packet)
		}

		if useRabbitMQ {
			// Set message to be non-persistent by default
			var deliveryMode uint8 = 1

			if settings.RabbitMQ.Publish.Persistent {
				deliveryMode = 2
			}

			b, err := json.Marshal(headers)
			if err != nil {
				log.Println("Failed to marshal packet to JSON:", err, packet)
				// Skip packet if JSON marshalling errors
				continue
			}
			// Send JSON to RabbitMQ exchange
			err = ch.Publish(
				settings.RabbitMQ.Exchange.Name,
				settings.RabbitMQ.Publish.Key,
				settings.RabbitMQ.Publish.Mandatory,
				settings.RabbitMQ.Publish.Immediate,
				amqp.Publishing{
					ContentType:  "text/json",
					DeliveryMode: deliveryMode,
					Body:         b,
				})
			failOnError(err, "Failed to publish a message")
		} else {
			// Pretty print JSON when sending to standard output
			b, err := json.MarshalIndent(headers, "", "  ")
			if err != nil {
				log.Println("Failed to marshal packet to JSON:", err, packet)
				// Skip packet if JSON marshalling errors
				continue
			}
			fmt.Println(string(b))
			fmt.Println()
		}
	}
}

func main() {
	// Set command line flags
	device := flag.String("device", "eth0", "Device to sniff")
	snaplen := flag.Int("snaplen", 65535, "Snapshot length")
	promiscuous := flag.Bool("promiscuous", false, "Set promiscuous mode")
	timeout := flag.Duration("timeout", pcap.BlockForever, "Timeout")
	filter := flag.String("filter", "", "Berkley Packet Filter (BPF)")
	showVersion := flag.Bool("version", false, "Show version")
	logFilePath := flag.String("log", "./nose-bleed.log", "Path to log file")
	configPath := flag.String("config", "", "Path to configuration file in JSON format")

	flag.Parse()

	// Show version and exit if version flag is set
	if *showVersion {
		fmt.Println(version)
		os.Exit(0)
	}

	// Configure logging
	logFile, err := os.OpenFile(*logFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Failed to open log file:", err)
		os.Exit(1)
	}
	defer logFile.Close()
	log.SetOutput(logFile)

	// Get settings
	settings := new(Settings)
	if *configPath != "" {
		s, err := ioutil.ReadFile(*configPath)
		if err != nil {
			log.Fatalln("Failed to get settings:", err)
		}

		if err := json.Unmarshal(s, settings); err != nil {
			log.Fatalln("Failed to unmarshal JSON settings:", err)
		}
	}

	// Start sniffing
	sniff(*device, *snaplen, *promiscuous, *timeout, *filter, settings)

}
<commit_msg>Bump version to 0.5.0<commit_after>package main

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"time"

	"github.com/kbrebanov/nose-bleed/parser"

	"github.com/google/gopacket"
	"github.com/google/gopacket/pcap"
	"github.com/streadway/amqp"
)

const version string = "0.5.0"

// RabbitMQPublishSettings is a structure for RabbitMQ publish settings
type RabbitMQPublishSettings struct {
	Key        string `json:"key"`
	Mandatory  bool   `json:"mandatory"`
	Immediate  bool   `json:"immediate"`
	Persistent bool   `json:"persistent"`
}

// RabbitMQExchangeSettings is a structure for RabbitMQ exchange settings
type RabbitMQExchangeSettings struct {
	Name       string `json:"name"`
	Type       string `json:"type"`
	Durable    bool   `json:"durable"`
	AutoDelete bool   `json:"auto_delete"`
	Internal   bool   `json:"internal"`
	NoWait     bool   `json:"no_wait"`
}

// RabbitMQTLSSettings is a structure for RabbitMQ TLS settings
type RabbitMQTLSSettings struct {
	Enabled    bool   `json:"enabled"`
	CACertFile string `json:"ca_cert_file"`
	CertFile   string `json:"cert_file"`
	KeyFile    string `json:"key_file"`
}

// RabbitMQSettings is a structure for RabbitMQ settings
type RabbitMQSettings struct {
	User     string                   `json:"user"`
	Password string                   `json:"password"`
	Host     string                   `json:"host"`
	Port     int                      `json:"port"`
	VHost    string                   `json:"vhost"`
	TLS      RabbitMQTLSSettings      `json:"tls"`
	Exchange RabbitMQExchangeSettings `json:"exchange"`
	Publish  RabbitMQPublishSettings  `json:"publish"`
}

// Settings is a structure for configuration settings
type Settings struct {
	RabbitMQ RabbitMQSettings `json:"rabbitmq,omitempty"`
}

// RabbitMQ error handler
func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

// sniff starts a live capture of network packets, parses and outputs
// the JSON results to either standard output or a RabbitMQ exchange.
func sniff(deviceName string, snapshotLen int, promiscuous bool, timeout time.Duration,
	filter string, settings *Settings) {

	var ch *amqp.Channel
	var conn *amqp.Connection
	var vhost string

	useRabbitMQ := false

	if settings.RabbitMQ.User != "" && settings.RabbitMQ.Password != "" && settings.RabbitMQ.Host != "" &&
		settings.RabbitMQ.Exchange.Name != "" && settings.RabbitMQ.Exchange.Type != "" {
		useRabbitMQ = true
	}

	if settings.RabbitMQ.VHost == "" {
		vhost = "/"
	} else {
		vhost = "/" + settings.RabbitMQ.VHost
	}

	// Initialize msg queue
	if useRabbitMQ {
		if settings.RabbitMQ.TLS.Enabled {
			tlsConfig := new(tls.Config)
			tlsConfig.RootCAs = x509.NewCertPool()

			if ca, err := ioutil.ReadFile(settings.RabbitMQ.TLS.CACertFile); err == nil {
				tlsConfig.RootCAs.AppendCertsFromPEM(ca)
			}

			if cert, err := tls.LoadX509KeyPair(settings.RabbitMQ.TLS.CertFile, settings.RabbitMQ.TLS.KeyFile); err == nil {
				tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
			}

			var err error
			conn, err = amqp.DialTLS(
				fmt.Sprintf("amqps://%s:%s@%s%s",
					settings.RabbitMQ.User,
					settings.RabbitMQ.Password,
					fmt.Sprintf("%s:%d", settings.RabbitMQ.Host, settings.RabbitMQ.Port),
					vhost),
				tlsConfig)
			failOnError(err, "Failed to connect to RabbitMQ using TLS")
			defer conn.Close()
		} else {
			var err error
			conn, err = amqp.Dial(
				fmt.Sprintf("amqp://%s:%s@%s%s",
					settings.RabbitMQ.User,
					settings.RabbitMQ.Password,
					fmt.Sprintf("%s:%d", settings.RabbitMQ.Host, settings.RabbitMQ.Port),
					vhost))
			failOnError(err, "Failed to connect to RabbitMQ")
			defer conn.Close()
		}

		var err error

		// Create a channel
		ch, err = conn.Channel()
		failOnError(err, "Failed to open a channel")
		defer ch.Close()

		// Declare an exchange
		err = ch.ExchangeDeclare(
			settings.RabbitMQ.Exchange.Name,
			settings.RabbitMQ.Exchange.Type,
			settings.RabbitMQ.Exchange.Durable,
			settings.RabbitMQ.Exchange.AutoDelete,
			settings.RabbitMQ.Exchange.Internal,
			settings.RabbitMQ.Exchange.NoWait,
			nil)
		failOnError(err, "Failed to declare an exchange")
	}

	// Start a live capture
	handle, err := pcap.OpenLive(deviceName, int32(snapshotLen), promiscuous, timeout)
	if err != nil {
		log.Fatalln("Failed to start packet capture:", err)
	}
	defer handle.Close()

	// Set filter
	if filter != "" {
		err = handle.SetBPFFilter(filter)
		if err != nil {
			log.Println("Failed to set BPF:", err)
		}
	}

	// Parse each packet
	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
	for packet := range packetSource.Packets() {
		headers, err := parser.Parse(packet)
		if err != nil {
			log.Println("Failed to parse packet:", err, packet)
		}

		if useRabbitMQ {
			// Set message to be non-persistent by default
			var deliveryMode uint8 = 1

			if settings.RabbitMQ.Publish.Persistent {
				deliveryMode = 2
			}

			b, err := json.Marshal(headers)
			if err != nil {
				log.Println("Failed to marshal packet to JSON:", err, packet)
				// Skip packet if JSON marshalling errors
				continue
			}
			// Send JSON to RabbitMQ exchange
			err = ch.Publish(
				settings.RabbitMQ.Exchange.Name,
				settings.RabbitMQ.Publish.Key,
				settings.RabbitMQ.Publish.Mandatory,
				settings.RabbitMQ.Publish.Immediate,
				amqp.Publishing{
					ContentType:  "text/json",
					DeliveryMode: deliveryMode,
					Body:         b,
				})
			failOnError(err, "Failed to publish a message")
		} else {
			// Pretty print JSON when sending to standard output
			b, err := json.MarshalIndent(headers, "", "  ")
			if err != nil {
				log.Println("Failed to marshal packet to JSON:", err, packet)
				// Skip packet if JSON marshalling errors
				continue
			}
			fmt.Println(string(b))
			fmt.Println()
		}
	}
}

func main() {
	// Set command line flags
	device := flag.String("device", "eth0", "Device to sniff")
	snaplen := flag.Int("snaplen", 65535, "Snapshot length")
	promiscuous := flag.Bool("promiscuous", false, "Set promiscuous mode")
	timeout := flag.Duration("timeout", pcap.BlockForever, "Timeout")
	filter := flag.String("filter", "", "Berkley Packet Filter (BPF)")
	showVersion := flag.Bool("version", false, "Show version")
	logFilePath := flag.String("log", "./nose-bleed.log", "Path to log file")
	configPath := flag.String("config", "", "Path to configuration file in JSON format")

	flag.Parse()

	// Show version and exit if version flag is set
	if *showVersion {
		fmt.Println(version)
		os.Exit(0)
	}

	// Configure logging
	logFile, err := os.OpenFile(*logFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Failed to open log file:", err)
		os.Exit(1)
	}
	defer logFile.Close()
	log.SetOutput(logFile)

	// Get settings
	settings := new(Settings)
	if *configPath != "" {
		s, err := ioutil.ReadFile(*configPath)
		if err != nil {
			log.Fatalln("Failed to get settings:", err)
		}

		if err := json.Unmarshal(s, settings); err != nil {
			log.Fatalln("Failed to unmarshal JSON settings:", err)
		}
	}

	// Start sniffing
	sniff(*device, *snaplen, *promiscuous, *timeout, *filter, settings)

}
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package reporter

import (
	"fmt"
	"io"

	"github.com/getgauge/gauge/logger"
)

type simpleConsole struct {
	indentation int
	writer      io.Writer
}

func newSimpleConsole(out io.Writer) *simpleConsole {
	return &simpleConsole{writer: out}
}

func (sc *simpleConsole) SpecStart(heading string) {
	formattedHeading := formatSpec(heading)
	logger.GaugeLog.Info(formattedHeading)
	fmt.Fprint(sc.writer, fmt.Sprintf("%s%s", formattedHeading, newline))
}

func (sc *simpleConsole) SpecEnd() {
	fmt.Fprintln(sc.writer)
}

func (sc *simpleConsole) ScenarioStart(heading string) {
	sc.indentation += scenarioIndentation
	formattedHeading := formatScenario(heading)
	logger.GaugeLog.Info(formattedHeading)
	fmt.Fprint(sc.writer, fmt.Sprintf("%s%s", indent(formattedHeading, sc.indentation), newline))
}

func (sc *simpleConsole) ScenarioEnd(failed bool) {
	sc.indentation -= scenarioIndentation
}

func (sc *simpleConsole) StepStart(stepText string) {
	sc.indentation += stepIndentation
	logger.GaugeLog.Debug(stepText)
	if Verbose {
		fmt.Fprint(sc.writer, fmt.Sprintf("%s%s", indent(stepText, sc.indentation), newline))
	}
}

func (sc *simpleConsole) StepEnd(failed bool) {
	sc.indentation -= stepIndentation
}

func (sc *simpleConsole) ConceptStart(conceptHeading string) {
	sc.indentation += stepIndentation
	logger.GaugeLog.Debug(conceptHeading)
	if Verbose {
		fmt.Fprint(sc.writer, fmt.Sprintf("%s%s", indent(conceptHeading, sc.indentation), newline))
	}
}

func (sc *simpleConsole) ConceptEnd(failed bool) {
	sc.indentation -= stepIndentation
}

func (sc *simpleConsole) DataTable(table string) {
	logger.GaugeLog.Debug(table)
	fmt.Fprint(sc.writer, fmt.Sprintf("%s%s", newline, table))
}

func (sc *simpleConsole) Error(err string, args ...interface{}) {
	errorMessage := fmt.Sprintf(err, args...)
	logger.GaugeLog.Error(errorMessage)
	errorString := indent(errorMessage, sc.indentation+sysoutIndentation)
	fmt.Fprint(sc.writer, fmt.Sprintf("%s%s", errorString, newline))
}

func (sc *simpleConsole) Write(b []byte) (int, error) {
	if Verbose {
		formattedString := fmt.Sprintf("%s%s", spaces(sc.indentation+sysoutIndentation), string(b))
		fmt.Fprint(sc.writer, formattedString)
		return len(b), nil
	}
	return 0, nil
}
<commit_msg>Write returns len(b) to avoid short write error<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package reporter

import (
	"fmt"
	"io"

	"github.com/getgauge/gauge/logger"
)

type simpleConsole struct {
	indentation int
	writer      io.Writer
}

func newSimpleConsole(out io.Writer) *simpleConsole {
	return &simpleConsole{writer: out}
}

func (sc *simpleConsole) SpecStart(heading string) {
	formattedHeading := formatSpec(heading)
	logger.GaugeLog.Info(formattedHeading)
	fmt.Fprint(sc.writer, fmt.Sprintf("%s%s", formattedHeading, newline))
}

func (sc *simpleConsole) SpecEnd() {
	fmt.Fprintln(sc.writer)
}

func (sc *simpleConsole) ScenarioStart(heading string) {
	sc.indentation += scenarioIndentation
	formattedHeading := formatScenario(heading)
	logger.GaugeLog.Info(formattedHeading)
	fmt.Fprint(sc.writer, fmt.Sprintf("%s%s", indent(formattedHeading, sc.indentation), newline))
}

func (sc *simpleConsole) ScenarioEnd(failed bool) {
	sc.indentation -= scenarioIndentation
}

func (sc *simpleConsole) StepStart(stepText string) {
	sc.indentation += stepIndentation
	logger.GaugeLog.Debug(stepText)
	if Verbose {
		fmt.Fprint(sc.writer, fmt.Sprintf("%s%s", indent(stepText, sc.indentation), newline))
	}
}

func (sc *simpleConsole) StepEnd(failed bool) {
	sc.indentation -= stepIndentation
}

func (sc *simpleConsole) ConceptStart(conceptHeading string) {
	sc.indentation += stepIndentation
	logger.GaugeLog.Debug(conceptHeading)
	if Verbose {
		fmt.Fprint(sc.writer, fmt.Sprintf("%s%s", indent(conceptHeading, sc.indentation), newline))
	}
}

func (sc *simpleConsole) ConceptEnd(failed bool) {
	sc.indentation -= stepIndentation
}

func (sc *simpleConsole) DataTable(table string) {
	logger.GaugeLog.Debug(table)
	fmt.Fprint(sc.writer, fmt.Sprintf("%s%s", newline, table))
}

func (sc *simpleConsole) Error(err string, args ...interface{}) {
	errorMessage := fmt.Sprintf(err, args...)
	logger.GaugeLog.Error(errorMessage)
	errorString := indent(errorMessage, sc.indentation+sysoutIndentation)
	fmt.Fprint(sc.writer, fmt.Sprintf("%s%s", errorString, newline))
}

func (sc *simpleConsole) Write(b []byte) (int, error) {
	if Verbose {
		formattedString := fmt.Sprintf("%s%s", spaces(sc.indentation+sysoutIndentation), string(b))
		fmt.Fprint(sc.writer, formattedString)
	}
	return len(b), nil
}
<|endoftext|>


<commit_before>package scrub

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"reflect"

	"code.gitea.io/git"
	"code.gitea.io/gitea/modules/log"
)

var JSON_FILES_TO_SCRUB = [...]string{
	"project.json",
	"package.json",
	"manifest.json",
	"status.json",
}

var JSON_FIELDS_TO_SCRUB = [...]string{
	"translators",
	"contributors",
	"checking_entity",
}

func ScrubJsonFiles(localPath string) error {
	for _, fileName := range JSON_FILES_TO_SCRUB {
		if err := ScrubJsonFile(localPath, fileName); err != nil {
			return err
		}
	}
	return nil
}

func ScrubJsonFile(localPath, fileName string) error {
	jsonPath := path.Join(localPath, fileName)

	var jsonData interface{}
	if _, err := os.Stat(jsonPath); os.IsNotExist(err) {
		return nil // path does not exist, nothing to scrub!
	} else if fileContent, err := ioutil.ReadFile(jsonPath); err != nil {
		log.Error(3, "%v", err)
		return err // error reading file
	} else {
		if err = json.Unmarshal(fileContent, &jsonData); err != nil {
			log.Error(3, "%v", err)
			return err // error unmarhalling file
		}
	}

	m := jsonData.(map[string]interface{})
	ScrubMap(m)

	if fileContent, err := json.MarshalIndent(m, "", "  "); err != nil {
		return err
	} else {
		if err := ScrubFile(localPath, fileName); err != nil {
			return err
		}
		if err := ioutil.WriteFile(jsonPath, []byte(fileContent), 0666); err != nil {
			return err
		}
	}

	return nil
}

func ScrubMap(m map[string]interface{}) {
	for _, field := range JSON_FIELDS_TO_SCRUB {
		if _, ok := m[field]; ok {
			m[field] = []string{}
		}
	}
	for _, v := range m {
		if reflect.ValueOf(v).Kind() == reflect.Map {
			vm := v.(map[string]interface{})
			ScrubMap(vm)
		}
	}
}

// ScrubFile completely removes a file from a repository's history
func ScrubFile(repoPath string, fileName string) error {
	gitPath, err := exec.LookPath("git")
	if err != nil {
		return err
	}
	cmd := git.NewCommand("filter-branch", "--force", "--prune-empty", "--tag-name-filter", "cat",
		"--index-filter", "\""+gitPath+"\" rm --cached --ignore-unmatch "+fileName,
		"--", "--all")
	_, err = cmd.RunInDir(repoPath)
	if err != nil && err.Error() == "exit status 1" {
		os.RemoveAll(path.Join(repoPath, ".git/refs/original/"))
		cmd = git.NewCommand("reflog", "expire", "--all")
		_, err = cmd.RunInDir(repoPath)
		if err != nil && err.Error() == "exit status 1" {
			cmd = git.NewCommand("gc", "--aggressive", "--prune")
			_, err = cmd.RunInDir(repoPath)
			return err
		}
	}
	return err
}

func ScrubCommitNameAndEmail(localPath, newName, newEmail string) error {
	os.RemoveAll(path.Join(localPath, ".git/refs/original/"))
	if _, err := git.NewCommand("filter-branch", "-f", "--env-filter", `
export GIT_COMMITTER_NAME="`+newName+`"
export GIT_COMMITTER_EMAIL="`+newEmail+`"
export GIT_AUTHOR_NAME="`+newName+`"
export GIT_AUTHOR_EMAIL="`+newEmail+`"
`, "--tag-name-filter", "cat", "--", "--branches", "--tags").RunInDir(localPath); err != nil {
		return err
	}
	if _, err := git.NewCommand("push", "--force", "--tags", "origin", "refs/heads/*").RunInDir(localPath); err != nil {
		return err
	}
	return nil
}
<commit_msg>Check errors in scrub code<commit_after>package scrub

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"reflect"

	"code.gitea.io/git"
	"code.gitea.io/gitea/modules/log"
)

var JSON_FILES_TO_SCRUB = [...]string{
	"project.json",
	"package.json",
	"manifest.json",
	"status.json",
}

var JSON_FIELDS_TO_SCRUB = [...]string{
	"translators",
	"contributors",
	"checking_entity",
}

func ScrubJsonFiles(localPath string) error {
	for _, fileName := range JSON_FILES_TO_SCRUB {
		if err := ScrubJsonFile(localPath, fileName); err != nil {
			return err
		}
	}
	return nil
}

func ScrubJsonFile(localPath, fileName string) error {
	jsonPath := path.Join(localPath, fileName)

	var jsonData interface{}
	if _, err := os.Stat(jsonPath); os.IsNotExist(err) {
		return nil // path does not exist, nothing to scrub!
	} else if fileContent, err := ioutil.ReadFile(jsonPath); err != nil {
		log.Error(3, "%v", err)
		return err // error reading file
	} else {
		if err = json.Unmarshal(fileContent, &jsonData); err != nil {
			log.Error(3, "%v", err)
			return err // error unmarhalling file
		}
	}

	m := jsonData.(map[string]interface{})
	ScrubMap(m)

	if fileContent, err := json.MarshalIndent(m, "", "  "); err != nil {
		return err
	} else {
		if err := ScrubFile(localPath, fileName); err != nil {
			return err
		}
		if err := ioutil.WriteFile(jsonPath, []byte(fileContent), 0666); err != nil {
			return err
		}
	}

	return nil
}

func ScrubMap(m map[string]interface{}) {
	for _, field := range JSON_FIELDS_TO_SCRUB {
		if _, ok := m[field]; ok {
			m[field] = []string{}
		}
	}
	for _, v := range m {
		if reflect.ValueOf(v).Kind() == reflect.Map {
			vm := v.(map[string]interface{})
			ScrubMap(vm)
		}
	}
}

// ScrubFile completely removes a file from a repository's history
func ScrubFile(repoPath string, fileName string) error {
	gitPath, err := exec.LookPath("git")
	if err != nil {
		return err
	}
	cmd := git.NewCommand("filter-branch", "--force", "--prune-empty", "--tag-name-filter", "cat",
		"--index-filter", "\""+gitPath+"\" rm --cached --ignore-unmatch "+fileName,
		"--", "--all")
	_, err = cmd.RunInDir(repoPath)
	if err != nil && err.Error() == "exit status 1" {
		err := os.RemoveAll(path.Join(repoPath, ".git/refs/original/"))
		if err != nil {
			return err
		}
		cmd = git.NewCommand("reflog", "expire", "--all")
		_, err = cmd.RunInDir(repoPath)
		if err != nil && err.Error() == "exit status 1" {
			cmd = git.NewCommand("gc", "--aggressive", "--prune")
			_, err = cmd.RunInDir(repoPath)
			return err
		}
	}
	return err
}

func ScrubCommitNameAndEmail(localPath, newName, newEmail string) error {
	if err := os.RemoveAll(path.Join(localPath, ".git/refs/original/")); err != nil {
		return err
	}
	if _, err := git.NewCommand("filter-branch", "-f", "--env-filter", `
export GIT_COMMITTER_NAME="`+newName+`"
export GIT_COMMITTER_EMAIL="`+newEmail+`"
export GIT_AUTHOR_NAME="`+newName+`"
export GIT_AUTHOR_EMAIL="`+newEmail+`"
`, "--tag-name-filter", "cat", "--", "--branches", "--tags").RunInDir(localPath); err != nil {
		return err
	}
	if _, err := git.NewCommand("push", "--force", "--tags", "origin", "refs/heads/*").RunInDir(localPath); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


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

package log4go

import (
	"os"
	"fmt"
	"time"
	"sync"
	"strings"
	"container/vector"
)

// This log writer sends output to a file
type FileLogWriter struct {
	// thread safety (TODO: goroutine+chans instead?)
	lock *sync.Mutex

	// The opened file
	filename string
	file  *os.File

	// The logging format
	format string

	// Rotate at linecount
	maxlines int
	maxlines_curlines int

	// Rotate at size
	maxsize int
	maxsize_cursize int

	// Rotate daily
	daily bool
	daily_opendate int

	// Keep old logfiles (.001, .002, etc)
	rotate bool
}

// Known format codes:
// %T - Time (15:04:05 MST)
// %t - Time (15:04)
// %D - Date (2006/01/02)
// %d - Date (01/02/06)
// %L - Level (FNST, FINE, DEBG, TRAC, WARN, EROR, CRIT)
// %S - Source
// %M - Message
// Ignores unknown formats
// Recommended: "[%D %T] [%L] (%S) %M"
func FormatLogRecord(format string, rec *LogRecord) string {
	var ovec vector.StringVector

	// Split the string into pieces by % signs
	pieces := strings.Split(format, "%", 0)
	ovec.Resize(0, 2*len(pieces)+2) // allocate enough pieces for each piece and its previous plus an extra for the first and last piece for good measure

	// Iterate over the pieces, replacing known formats
	for i, piece := range pieces {
		if i > 0 && len(piece) > 0 {
			switch piece[0] {
			case 'T':
				ovec.Push(rec.Created.Format("15:04:05 MST"))
			case 't':
				ovec.Push(rec.Created.Format("15:04"))
			case 'D':
				ovec.Push(rec.Created.Format("2006/01/02"))
			case 'd':
				ovec.Push(rec.Created.Format("01/02/06"))
			case 'L':
				ovec.Push(levelStrings[rec.Level])
			case 'S':
				ovec.Push(rec.Source)
			case 'M':
				ovec.Push(rec.Message)
			}
			if len(piece) > 1 {
				ovec.Push(piece[1:])
			}
		} else if len(piece) > 0 {
			ovec.Push(piece)
		}
	}

	return strings.Join(ovec, "")+"\n"
}

// This is the FileLogWriter's output method
func (flw *FileLogWriter) LogWrite(rec *LogRecord) (n int, err os.Error) {
	flw.lock.Lock()
	defer flw.lock.Unlock()

	// First, check if we've gone over any of our rotate triggers
	if flw.Good() {
		if (flw.maxlines > 0 && flw.maxlines_curlines >= flw.maxlines) ||
			(flw.maxsize > 0 && flw.maxsize_cursize >= flw.maxsize) ||
			(flw.daily && time.LocalTime().Day != flw.daily_opendate) {
			flw.intRotate()
		}
	}

	// Make sure the writer is (still) good
	if !flw.Good() {
		return -1, os.NewError("File was not opened successfully")
	}

	// Perform the write
	n,err = flw.file.Write([]byte(FormatLogRecord(flw.format, rec)))

	// Update the counts
	if err == nil {
		flw.maxlines_curlines++
		flw.maxsize_cursize += n
	}

	return n, err
}

func (flw *FileLogWriter) Good() bool {
	return flw.file != nil
}

func (flw *FileLogWriter) Close() {
	flw.file.Close()
	flw.file = nil
}

func NewFileLogWriter(fname string) *FileLogWriter {
	flw := new(FileLogWriter)
	flw.lock = new(sync.Mutex)
	flw.filename = fname
	flw.format = "[%D %T] [%L] (%S) %M"
	flw.file = nil

	flw.intRotate() // open the file for the first time

	return flw
}

// Request that the logs rotate
func (flw *FileLogWriter) Rotate() {
	flw.lock.Lock()
	defer flw.lock.Unlock()
	flw.intRotate()
}

// If this is called in a threaded context, it MUST be synchronized
func (flw *FileLogWriter) intRotate() {
	// Close any log file that may be open
	if flw.file != nil {
		flw.file.Close()
	}

	// If we are keeping log files, move it to the next available number
	if flw.rotate {
		_, err := os.Lstat(flw.filename)
		if err == nil { // file exists
			// Find the next available number
			num := 1
			fname := ""
			for ; err == nil && num < 999; num++ {
				fname = flw.filename + fmt.Sprintf(".%03d", num)
				_, err = os.Lstat(fname)
			}
			if err != nil {
				// Rename the file to its newfound home
				os.Rename(flw.filename, fname)
			} else {
				fmt.Fprintf(os.Stderr, "FileLogWriter.intRotate: Cannot find free log number to rename %s\n", flw.filename)
			}
		}
	}

	// Open the log file
	fd, err := os.Open(flw.filename, os.O_WRONLY|os.O_TRUNC|os.O_CREAT, 0660)
	if err != nil {
		fmt.Fprintf(os.Stderr, "FileLogWriter.intRotate: %s\n", err)
		return
	}
	flw.file = fd

	// Set the daily open date to the current date
	flw.daily_opendate = time.LocalTime().Day

	// initialize rotation values
	flw.maxlines_curlines = 0
	flw.maxsize_cursize = 0
}

// Set the logging format
func (flw *FileLogWriter) SetFormat(format string) {
	flw.format = format
}

// Set rotate at linecount
func (flw *FileLogWriter) SetRotateLines(maxlines int) {
	flw.maxlines = maxlines
}

// Set rotate at size
func (flw *FileLogWriter) SetRotateSize(maxsize int) {
	flw.maxsize = maxsize
}

// Set rotate daily
func (flw *FileLogWriter) SetRotateDaily(daily bool) {
	flw.daily = daily
}

// Set keep old
func (flw *FileLogWriter) SetRotate(rotate bool) {
	flw.rotate = rotate
}
<commit_msg>Added debugs.<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package log4go

import (
	"os"
	"fmt"
	"time"
	"sync"
	"strings"
	"container/vector"
)

// This log writer sends output to a file
type FileLogWriter struct {
	// thread safety (TODO: goroutine+chans instead?)
	lock *sync.Mutex

	// The opened file
	filename string
	file  *os.File

	// The logging format
	format string

	// Rotate at linecount
	maxlines int
	maxlines_curlines int

	// Rotate at size
	maxsize int
	maxsize_cursize int

	// Rotate daily
	daily bool
	daily_opendate int

	// Keep old logfiles (.001, .002, etc)
	rotate bool
}

// Known format codes:
// %T - Time (15:04:05 MST)
// %t - Time (15:04)
// %D - Date (2006/01/02)
// %d - Date (01/02/06)
// %L - Level (FNST, FINE, DEBG, TRAC, WARN, EROR, CRIT)
// %S - Source
// %M - Message
// Ignores unknown formats
// Recommended: "[%D %T] [%L] (%S) %M"
func FormatLogRecord(format string, rec *LogRecord) string {
	var ovec vector.StringVector

	// Split the string into pieces by % signs
	pieces := strings.Split(format, "%", 0)
	ovec.Resize(0, 2*len(pieces)+2) // allocate enough pieces for each piece and its previous plus an extra for the first and last piece for good measure

	// Iterate over the pieces, replacing known formats
	for i, piece := range pieces {
		if i > 0 && len(piece) > 0 {
			switch piece[0] {
			case 'T':
				ovec.Push(rec.Created.Format("15:04:05 MST"))
			case 't':
				ovec.Push(rec.Created.Format("15:04"))
			case 'D':
				ovec.Push(rec.Created.Format("2006/01/02"))
			case 'd':
				ovec.Push(rec.Created.Format("01/02/06"))
			case 'L':
				ovec.Push(levelStrings[rec.Level])
			case 'S':
				ovec.Push(rec.Source)
			case 'M':
				ovec.Push(rec.Message)
			}
			if len(piece) > 1 {
				ovec.Push(piece[1:])
			}
		} else if len(piece) > 0 {
			ovec.Push(piece)
		}
	}

	return strings.Join(ovec, "")+"\n"
}

// This is the FileLogWriter's output method
func (flw *FileLogWriter) LogWrite(rec *LogRecord) (n int, err os.Error) {
	flw.lock.Lock()
	defer flw.lock.Unlock()

	// First, check if we've gone over any of our rotate triggers
	if flw.Good() {
		if (flw.maxlines > 0 && flw.maxlines_curlines >= flw.maxlines) ||
			(flw.maxsize > 0 && flw.maxsize_cursize >= flw.maxsize) ||
			(flw.daily && time.LocalTime().Day != flw.daily_opendate) {
			flw.intRotate()
		}
	}

	// Make sure the writer is (still) good
	if !flw.Good() {
		return -1, os.NewError("File was not opened successfully")
	}

	// Perform the write
	n,err = flw.file.Write([]byte(FormatLogRecord(flw.format, rec)))

	// Update the counts
	if err == nil {
		flw.maxlines_curlines++
		flw.maxsize_cursize += n
	}

	return n, err
}

func (flw *FileLogWriter) Good() bool {
	return flw.file != nil
}

func (flw *FileLogWriter) Close() {
	flw.file.Close()
	flw.file = nil
}

func NewFileLogWriter(fname string) *FileLogWriter {
	flw := new(FileLogWriter)
	flw.lock = new(sync.Mutex)
	flw.filename = fname
	flw.format = "[%D %T] [%L] (%S) %M"
	flw.file = nil

	flw.intRotate() // open the file for the first time

	return flw
}

// Request that the logs rotate
func (flw *FileLogWriter) Rotate() {
	flw.lock.Lock()
	defer flw.lock.Unlock()
	flw.intRotate()
}

// If this is called in a threaded context, it MUST be synchronized
func (flw *FileLogWriter) intRotate() {
	// Close any log file that may be open
	if flw.file != nil {
		flw.file.Close()
	}

	// If we are keeping log files, move it to the next available number
	if flw.rotate {
		_, err := os.Lstat(flw.filename)
		if err == nil { // file exists
			fmt.Fprintf(os.Stderr, "FileLogWriter.intRotate: file %s exists, searching for extension\n", flw.filename)
			// Find the next available number
			num := 1
			fname := ""
			for ; err == nil && num < 999; num++ {
				fname = flw.filename + fmt.Sprintf(".%03d", num)
				_, err = os.Lstat(fname)
			}
			if err != nil {
				// Rename the file to its newfound home
				fmt.Fprintf(os.Stderr, "FileLogWriter.intRotate: Moving %s to %s\n", flw.filename, fname)
				os.Rename(flw.filename, fname)
			} else {
				fmt.Fprintf(os.Stderr, "FileLogWriter.intRotate: Cannot find free log number to rename %s\n", flw.filename)
			}
		}
	}

	// Open the log file
	fd, err := os.Open(flw.filename, os.O_WRONLY|os.O_APPEND|os.O_CREAT, 0660)
	if err != nil {
		fmt.Fprintf(os.Stderr, "FileLogWriter.intRotate: %s\n", err)
		return
	}
	flw.file = fd

	// Set the daily open date to the current date
	flw.daily_opendate = time.LocalTime().Day

	// initialize rotation values
	flw.maxlines_curlines = 0
	flw.maxsize_cursize = 0
}

// Set the logging format
func (flw *FileLogWriter) SetFormat(format string) {
	flw.format = format
}

// Set rotate at linecount
func (flw *FileLogWriter) SetRotateLines(maxlines int) {
	flw.maxlines = maxlines
}

// Set rotate at size
func (flw *FileLogWriter) SetRotateSize(maxsize int) {
	flw.maxsize = maxsize
}

// Set rotate daily
func (flw *FileLogWriter) SetRotateDaily(daily bool) {
	flw.daily = daily
}

// Set keep old
func (flw *FileLogWriter) SetRotate(rotate bool) {
	flw.rotate = rotate
}
<|endoftext|>


<commit_before>package response

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"time"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
)

var debug bool

// Init sets the debug variable to the provided value.
func Init(d bool) {
	debug = d
}

// Response represents an API response
type Response interface {
	Render(w http.ResponseWriter) error
	String() string
}

// Sync response
type syncResponse struct {
	success   bool
	etag      interface{}
	metadata  interface{}
	location  string
	code      int
	headers   map[string]string
	plaintext bool
}

// EmptySyncResponse represents an empty syncResponse.
var EmptySyncResponse = &syncResponse{success: true, metadata: make(map[string]interface{})}

// SyncResponse returns a new syncResponse with the success and metadata fields
// set to the provided values.
func SyncResponse(success bool, metadata interface{}) Response {
	return &syncResponse{success: success, metadata: metadata}
}

// SyncResponseETag returns a new syncResponse with an etag.
func SyncResponseETag(success bool, metadata interface{}, etag interface{}) Response {
	return &syncResponse{success: success, metadata: metadata, etag: etag}
}

// SyncResponseLocation returns a new syncResponse with a location.
func SyncResponseLocation(success bool, metadata interface{}, location string) Response {
	return &syncResponse{success: success, metadata: metadata, location: location}
}

// SyncResponseRedirect returns a new syncResponse with a location, indicating
// a permanent redirect.
func SyncResponseRedirect(address string) Response {
	return &syncResponse{success: true, location: address, code: http.StatusPermanentRedirect}
}

// SyncResponseHeaders returns a new syncResponse with headers.
func SyncResponseHeaders(success bool, metadata interface{}, headers map[string]string) Response {
	return &syncResponse{success: success, metadata: metadata, headers: headers}
}

// SyncResponsePlain return a new syncResponse with plaintext.
func SyncResponsePlain(success bool, metadata string) Response {
	return &syncResponse{success: success, metadata: metadata, plaintext: true}
}

func (r *syncResponse) Render(w http.ResponseWriter) error {
	// Set an appropriate ETag header
	if r.etag != nil {
		etag, err := util.EtagHash(r.etag)
		if err == nil {
			w.Header().Set("ETag", fmt.Sprintf("\"%s\"", etag))
		}
	}

	// Prepare the JSON response
	status := api.Success
	if !r.success {
		status = api.Failure
	}

	if r.headers != nil {
		for h, v := range r.headers {
			w.Header().Set(h, v)
		}
	}

	if r.location != "" {
		w.Header().Set("Location", r.location)
		code := r.code
		if code == 0 {
			code = 201
		}
		w.WriteHeader(code)
	}

	if r.plaintext && r.metadata != nil {
		w.Header().Set("Content-Type", "text/plain")

		_, err := w.Write([]byte(r.metadata.(string)))
		if err != nil {
			return err
		}

		return nil
	}

	resp := api.ResponseRaw{
		Type:       api.SyncResponse,
		Status:     status.String(),
		StatusCode: int(status),
		Metadata:   r.metadata,
	}

	return util.WriteJSON(w, resp, debug)
}

func (r *syncResponse) String() string {
	if r.success {
		return "success"
	}

	return "failure"
}

// Error response
type errorResponse struct {
	code int
	msg  string
}

// ErrorResponse returns an error response with the given code and msg.
func ErrorResponse(code int, msg string) Response {
	return &errorResponse{code, msg}
}

// BadRequest returns a bad request response (400) with the given error.
func BadRequest(err error) Response {
	return &errorResponse{http.StatusBadRequest, err.Error()}
}

// Conflict returns a conflict response (409) with the given error.
func Conflict(err error) Response {
	message := "already exists"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusConflict, message}
}

// Forbidden returns a forbidden response (403) with the given error.
func Forbidden(err error) Response {
	message := "not authorized"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusForbidden, message}
}

// InternalError returns an internal error response (500) with the given error.
func InternalError(err error) Response {
	return &errorResponse{http.StatusInternalServerError, err.Error()}
}

// NotFound returns a not found response (404) with the given error.
func NotFound(err error) Response {
	message := "not found"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusNotFound, message}
}

// NotImplemented returns a not implemented response (501) with the given error.
func NotImplemented(err error) Response {
	message := "not implemented"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusNotImplemented, message}
}

// PreconditionFailed returns a precondition failed response (412) with the
// given error.
func PreconditionFailed(err error) Response {
	return &errorResponse{http.StatusPreconditionFailed, err.Error()}
}

// Unavailable return an unavailable response (503) with the given error.
func Unavailable(err error) Response {
	message := "unavailable"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusServiceUnavailable, message}
}

func (r *errorResponse) String() string {
	return r.msg
}

func (r *errorResponse) Render(w http.ResponseWriter) error {
	var output io.Writer

	buf := &bytes.Buffer{}
	output = buf
	var captured *bytes.Buffer
	if debug {
		captured = &bytes.Buffer{}
		output = io.MultiWriter(buf, captured)
	}

	err := json.NewEncoder(output).Encode(shared.Jmap{"type": api.ErrorResponse, "error": r.msg, "error_code": r.code})

	if err != nil {
		return err
	}

	if debug {
		shared.DebugJson(captured)
	}

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("X-Content-Type-Options", "nosniff")
	w.WriteHeader(r.code)
	fmt.Fprintln(w, buf.String())

	return nil
}

// FileResponseEntry represents a file response entry.
type FileResponseEntry struct {
	Identifier string
	Path       string
	Filename   string
	Buffer     []byte /* either a path or a buffer must be provided */
}

type fileResponse struct {
	req              *http.Request
	files            []FileResponseEntry
	headers          map[string]string
	removeAfterServe bool
}

// FileResponse returns a new file response.
func FileResponse(r *http.Request, files []FileResponseEntry, headers map[string]string, removeAfterServe bool) Response {
	return &fileResponse{r, files, headers, removeAfterServe}
}

func (r *fileResponse) Render(w http.ResponseWriter) error {
	if r.headers != nil {
		for k, v := range r.headers {
			w.Header().Set(k, v)
		}
	}

	// No file, well, it's easy then
	if len(r.files) == 0 {
		return nil
	}

	// For a single file, return it inline
	if len(r.files) == 1 {
		var rs io.ReadSeeker
		var mt time.Time
		var sz int64

		if r.files[0].Path == "" {
			rs = bytes.NewReader(r.files[0].Buffer)
			mt = time.Now()
			sz = int64(len(r.files[0].Buffer))
		} else {
			f, err := os.Open(r.files[0].Path)
			if err != nil {
				return err
			}
			defer f.Close()

			fi, err := f.Stat()
			if err != nil {
				return err
			}

			mt = fi.ModTime()
			sz = fi.Size()
			rs = f
		}

		w.Header().Set("Content-Type", "application/octet-stream")
		w.Header().Set("Content-Length", fmt.Sprintf("%d", sz))
		w.Header().Set("Content-Disposition", fmt.Sprintf("inline;filename=%s", r.files[0].Filename))

		http.ServeContent(w, r.req, r.files[0].Filename, mt, rs)
		if r.files[0].Path != "" && r.removeAfterServe {
			err := os.Remove(r.files[0].Path)
			if err != nil {
				return err
			}
		}

		return nil
	}

	// Now the complex multipart answer.
	mw := multipart.NewWriter(w)
	defer mw.Close()

	w.Header().Set("Content-Type", mw.FormDataContentType())
	w.Header().Set("Transfer-Encoding", "chunked")

	for _, entry := range r.files {
		var rd io.Reader
		if entry.Path != "" {
			fd, err := os.Open(entry.Path)
			if err != nil {
				return err
			}
			defer fd.Close()

			rd = fd
		} else {
			rd = bytes.NewReader(entry.Buffer)
		}

		fw, err := mw.CreateFormFile(entry.Identifier, entry.Filename)
		if err != nil {
			return err
		}

		_, err = io.Copy(fw, rd)
		if err != nil {
			return err
		}
	}

	return nil
}

func (r *fileResponse) String() string {
	return fmt.Sprintf("%d files", len(r.files))
}

type forwardedResponse struct {
	client  lxd.InstanceServer
	request *http.Request
}

// ForwardedResponse takes a request directed to a node and forwards it to
// another node, writing back the response it gegs.
func ForwardedResponse(client lxd.InstanceServer, request *http.Request) Response {
	return &forwardedResponse{
		client:  client,
		request: request,
	}
}

func (r *forwardedResponse) Render(w http.ResponseWriter) error {
	info, err := r.client.GetConnectionInfo()
	if err != nil {
		return err
	}

	url := fmt.Sprintf("%s%s", info.Addresses[0], r.request.URL.RequestURI())
	forwarded, err := http.NewRequest(r.request.Method, url, r.request.Body)
	if err != nil {
		return err
	}

	for key := range r.request.Header {
		forwarded.Header.Set(key, r.request.Header.Get(key))
	}

	httpClient, err := r.client.GetHTTPClient()
	if err != nil {
		return err
	}

	response, err := httpClient.Do(forwarded)
	if err != nil {
		return err
	}

	for key := range response.Header {
		w.Header().Set(key, response.Header.Get(key))
	}

	w.WriteHeader(response.StatusCode)
	_, err = io.Copy(w, response.Body)
	return err
}

func (r *forwardedResponse) String() string {
	return fmt.Sprintf("request to %s", r.request.URL)
}
<commit_msg>lxd/response/response: Reworks syncResponse to use util.WriteJSON<commit_after>package response

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"time"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	log "github.com/lxc/lxd/shared/log15"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
)

var debug bool

// Init sets the debug variable to the provided value.
func Init(d bool) {
	debug = d
}

// Response represents an API response
type Response interface {
	Render(w http.ResponseWriter) error
	String() string
}

// Sync response
type syncResponse struct {
	success   bool
	etag      interface{}
	metadata  interface{}
	location  string
	code      int
	headers   map[string]string
	plaintext bool
}

// EmptySyncResponse represents an empty syncResponse.
var EmptySyncResponse = &syncResponse{success: true, metadata: make(map[string]interface{})}

// SyncResponse returns a new syncResponse with the success and metadata fields
// set to the provided values.
func SyncResponse(success bool, metadata interface{}) Response {
	return &syncResponse{success: success, metadata: metadata}
}

// SyncResponseETag returns a new syncResponse with an etag.
func SyncResponseETag(success bool, metadata interface{}, etag interface{}) Response {
	return &syncResponse{success: success, metadata: metadata, etag: etag}
}

// SyncResponseLocation returns a new syncResponse with a location.
func SyncResponseLocation(success bool, metadata interface{}, location string) Response {
	return &syncResponse{success: success, metadata: metadata, location: location}
}

// SyncResponseRedirect returns a new syncResponse with a location, indicating
// a permanent redirect.
func SyncResponseRedirect(address string) Response {
	return &syncResponse{success: true, location: address, code: http.StatusPermanentRedirect}
}

// SyncResponseHeaders returns a new syncResponse with headers.
func SyncResponseHeaders(success bool, metadata interface{}, headers map[string]string) Response {
	return &syncResponse{success: success, metadata: metadata, headers: headers}
}

// SyncResponsePlain return a new syncResponse with plaintext.
func SyncResponsePlain(success bool, metadata string) Response {
	return &syncResponse{success: success, metadata: metadata, plaintext: true}
}

func (r *syncResponse) Render(w http.ResponseWriter) error {
	// Set an appropriate ETag header
	if r.etag != nil {
		etag, err := util.EtagHash(r.etag)
		if err == nil {
			w.Header().Set("ETag", fmt.Sprintf("\"%s\"", etag))
		}
	}

	// Prepare the JSON response
	status := api.Success
	if !r.success {
		status = api.Failure
	}

	if r.headers != nil {
		for h, v := range r.headers {
			w.Header().Set(h, v)
		}
	}

	code := r.code

	if r.location != "" {
		w.Header().Set("Location", r.location)
		if code == 0 {
			code = 201
		}
	}

	// Handle plain text headers.
	if r.plaintext {
		w.Header().Set("Content-Type", "text/plain")
	}

	// Write header and status code.
	if code == 0 {
		code = http.StatusOK
	}

	w.WriteHeader(code)

	// Handle plain text responses.
	if r.plaintext {
		if r.metadata != nil {
			_, err := w.Write([]byte(r.metadata.(string)))
			if err != nil {
				return err
			}
		}

		return nil
	}

	// Handle JSON responses.
	resp := api.ResponseRaw{
		Type:       api.SyncResponse,
		Status:     status.String(),
		StatusCode: int(status),
		Metadata:   r.metadata,
	}

	var debugLogger logger.Logger
	if debug {
		debugLogger = logging.AddContext(logger.Log, log.Ctx{"http_code": code})
	}

	return util.WriteJSON(w, resp, debugLogger)
}

func (r *syncResponse) String() string {
	if r.success {
		return "success"
	}

	return "failure"
}

// Error response
type errorResponse struct {
	code int
	msg  string
}

// ErrorResponse returns an error response with the given code and msg.
func ErrorResponse(code int, msg string) Response {
	return &errorResponse{code, msg}
}

// BadRequest returns a bad request response (400) with the given error.
func BadRequest(err error) Response {
	return &errorResponse{http.StatusBadRequest, err.Error()}
}

// Conflict returns a conflict response (409) with the given error.
func Conflict(err error) Response {
	message := "already exists"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusConflict, message}
}

// Forbidden returns a forbidden response (403) with the given error.
func Forbidden(err error) Response {
	message := "not authorized"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusForbidden, message}
}

// InternalError returns an internal error response (500) with the given error.
func InternalError(err error) Response {
	return &errorResponse{http.StatusInternalServerError, err.Error()}
}

// NotFound returns a not found response (404) with the given error.
func NotFound(err error) Response {
	message := "not found"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusNotFound, message}
}

// NotImplemented returns a not implemented response (501) with the given error.
func NotImplemented(err error) Response {
	message := "not implemented"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusNotImplemented, message}
}

// PreconditionFailed returns a precondition failed response (412) with the
// given error.
func PreconditionFailed(err error) Response {
	return &errorResponse{http.StatusPreconditionFailed, err.Error()}
}

// Unavailable return an unavailable response (503) with the given error.
func Unavailable(err error) Response {
	message := "unavailable"
	if err != nil {
		message = err.Error()
	}

	return &errorResponse{http.StatusServiceUnavailable, message}
}

func (r *errorResponse) String() string {
	return r.msg
}

func (r *errorResponse) Render(w http.ResponseWriter) error {
	var output io.Writer

	buf := &bytes.Buffer{}
	output = buf
	var captured *bytes.Buffer
	if debug {
		captured = &bytes.Buffer{}
		output = io.MultiWriter(buf, captured)
	}

	err := json.NewEncoder(output).Encode(shared.Jmap{"type": api.ErrorResponse, "error": r.msg, "error_code": r.code})

	if err != nil {
		return err
	}

	if debug {
		shared.DebugJson(captured)
	}

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("X-Content-Type-Options", "nosniff")
	w.WriteHeader(r.code)
	fmt.Fprintln(w, buf.String())

	return nil
}

// FileResponseEntry represents a file response entry.
type FileResponseEntry struct {
	Identifier string
	Path       string
	Filename   string
	Buffer     []byte /* either a path or a buffer must be provided */
}

type fileResponse struct {
	req              *http.Request
	files            []FileResponseEntry
	headers          map[string]string
	removeAfterServe bool
}

// FileResponse returns a new file response.
func FileResponse(r *http.Request, files []FileResponseEntry, headers map[string]string, removeAfterServe bool) Response {
	return &fileResponse{r, files, headers, removeAfterServe}
}

func (r *fileResponse) Render(w http.ResponseWriter) error {
	if r.headers != nil {
		for k, v := range r.headers {
			w.Header().Set(k, v)
		}
	}

	// No file, well, it's easy then
	if len(r.files) == 0 {
		return nil
	}

	// For a single file, return it inline
	if len(r.files) == 1 {
		var rs io.ReadSeeker
		var mt time.Time
		var sz int64

		if r.files[0].Path == "" {
			rs = bytes.NewReader(r.files[0].Buffer)
			mt = time.Now()
			sz = int64(len(r.files[0].Buffer))
		} else {
			f, err := os.Open(r.files[0].Path)
			if err != nil {
				return err
			}
			defer f.Close()

			fi, err := f.Stat()
			if err != nil {
				return err
			}

			mt = fi.ModTime()
			sz = fi.Size()
			rs = f
		}

		w.Header().Set("Content-Type", "application/octet-stream")
		w.Header().Set("Content-Length", fmt.Sprintf("%d", sz))
		w.Header().Set("Content-Disposition", fmt.Sprintf("inline;filename=%s", r.files[0].Filename))

		http.ServeContent(w, r.req, r.files[0].Filename, mt, rs)
		if r.files[0].Path != "" && r.removeAfterServe {
			err := os.Remove(r.files[0].Path)
			if err != nil {
				return err
			}
		}

		return nil
	}

	// Now the complex multipart answer.
	mw := multipart.NewWriter(w)
	defer mw.Close()

	w.Header().Set("Content-Type", mw.FormDataContentType())
	w.Header().Set("Transfer-Encoding", "chunked")

	for _, entry := range r.files {
		var rd io.Reader
		if entry.Path != "" {
			fd, err := os.Open(entry.Path)
			if err != nil {
				return err
			}
			defer fd.Close()

			rd = fd
		} else {
			rd = bytes.NewReader(entry.Buffer)
		}

		fw, err := mw.CreateFormFile(entry.Identifier, entry.Filename)
		if err != nil {
			return err
		}

		_, err = io.Copy(fw, rd)
		if err != nil {
			return err
		}
	}

	return nil
}

func (r *fileResponse) String() string {
	return fmt.Sprintf("%d files", len(r.files))
}

type forwardedResponse struct {
	client  lxd.InstanceServer
	request *http.Request
}

// ForwardedResponse takes a request directed to a node and forwards it to
// another node, writing back the response it gegs.
func ForwardedResponse(client lxd.InstanceServer, request *http.Request) Response {
	return &forwardedResponse{
		client:  client,
		request: request,
	}
}

func (r *forwardedResponse) Render(w http.ResponseWriter) error {
	info, err := r.client.GetConnectionInfo()
	if err != nil {
		return err
	}

	url := fmt.Sprintf("%s%s", info.Addresses[0], r.request.URL.RequestURI())
	forwarded, err := http.NewRequest(r.request.Method, url, r.request.Body)
	if err != nil {
		return err
	}

	for key := range r.request.Header {
		forwarded.Header.Set(key, r.request.Header.Get(key))
	}

	httpClient, err := r.client.GetHTTPClient()
	if err != nil {
		return err
	}

	response, err := httpClient.Do(forwarded)
	if err != nil {
		return err
	}

	for key := range response.Header {
		w.Header().Set(key, response.Header.Get(key))
	}

	w.WriteHeader(response.StatusCode)
	_, err = io.Copy(w, response.Body)
	return err
}

func (r *forwardedResponse) String() string {
	return fmt.Sprintf("request to %s", r.request.URL)
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package routes

import (
	restful "github.com/emicklei/go-restful/v3"
	"k8s.io/klog/v2"

	"k8s.io/apiserver/pkg/server/mux"
	builder2 "k8s.io/kube-openapi/pkg/builder"
	"k8s.io/kube-openapi/pkg/builder3"
	"k8s.io/kube-openapi/pkg/common"
	"k8s.io/kube-openapi/pkg/handler"
	"k8s.io/kube-openapi/pkg/handler3"
	"k8s.io/kube-openapi/pkg/validation/spec"
)

// OpenAPI installs spec endpoints for each web service.
type OpenAPI struct {
	Config *common.Config
}

// Install adds the SwaggerUI webservice to the given mux.
func (oa OpenAPI) InstallV2(c *restful.Container, mux *mux.PathRecorderMux) (*handler.OpenAPIService, *spec.Swagger) {
	spec, err := builder2.BuildOpenAPISpec(c.RegisteredWebServices(), oa.Config)
	if err != nil {
		klog.Fatalf("Failed to build open api spec for root: %v", err)
	}
	spec.Definitions = handler.PruneDefaults(spec.Definitions)
	openAPIVersionedService, err := handler.NewOpenAPIService(spec)
	if err != nil {
		klog.Fatalf("Failed to create OpenAPIService: %v", err)
	}

	err = openAPIVersionedService.RegisterOpenAPIVersionedService("/openapi/v2", mux)
	if err != nil {
		klog.Fatalf("Failed to register versioned open api spec for root: %v", err)
	}

	return openAPIVersionedService, spec
}

// InstallV3 adds the static group/versions defined in the RegisteredWebServices to the OpenAPI v3 spec
func (oa OpenAPI) InstallV3(c *restful.Container, mux *mux.PathRecorderMux) *handler3.OpenAPIService {
	openAPIVersionedService, err := handler3.NewOpenAPIService(nil)
	if err != nil {
		klog.Fatalf("Failed to create OpenAPIService: %v", err)
	}

	err = openAPIVersionedService.RegisterOpenAPIV3VersionedService("/openapi/v3", mux)
	if err != nil {
		klog.Fatalf("Failed to register versioned open api spec for root: %v", err)
	}

	grouped := make(map[string][]*restful.WebService)

	for _, t := range c.RegisteredWebServices() {
		// Strip the "/" prefix from the name
		gvName := t.RootPath()[1:]
		grouped[gvName] = []*restful.WebService{t}
	}

	for gv, ws := range grouped {
		spec, err := builder3.BuildOpenAPISpec(ws, oa.Config)
		if err != nil {
			klog.Errorf("Failed to build OpenAPI v3 for group %s, %q", gv, err)

		}
		openAPIVersionedService.UpdateGroupVersion(gv, spec)
	}
	return openAPIVersionedService
}
<commit_msg>UPSTREAM: <carry>: filter out CustomResourceQuota paths from OpenAPI<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package routes

import (
	"strings"

	restful "github.com/emicklei/go-restful/v3"
	"k8s.io/klog/v2"

	"k8s.io/apiserver/pkg/server/mux"
	builder2 "k8s.io/kube-openapi/pkg/builder"
	"k8s.io/kube-openapi/pkg/builder3"
	"k8s.io/kube-openapi/pkg/common"
	"k8s.io/kube-openapi/pkg/handler"
	"k8s.io/kube-openapi/pkg/handler3"
	"k8s.io/kube-openapi/pkg/validation/spec"
)

// OpenAPI installs spec endpoints for each web service.
type OpenAPI struct {
	Config *common.Config
}

// Install adds the SwaggerUI webservice to the given mux.
func (oa OpenAPI) InstallV2(c *restful.Container, mux *mux.PathRecorderMux) (*handler.OpenAPIService, *spec.Swagger) {
	// we shadow ClustResourceQuotas, RoleBindingRestrictions, and SecurityContextContstraints
	// with a CRD. This loop removes all CRQ,RBR, SCC paths
	// from the OpenAPI spec such that they don't conflict with the CRD
	// apiextensions-apiserver spec during merging.
	oa.Config.IgnorePrefixes = append(oa.Config.IgnorePrefixes,
		"/apis/quota.openshift.io/v1/clusterresourcequotas",
		"/apis/security.openshift.io/v1/securitycontextconstraints",
		"/apis/authorization.openshift.io/v1/rolebindingrestrictions",
		"/apis/authorization.openshift.io/v1/namespaces/{namespace}/rolebindingrestrictions",
		"/apis/authorization.openshift.io/v1/watch/namespaces/{namespace}/rolebindingrestrictions",
		"/apis/authorization.openshift.io/v1/watch/rolebindingrestrictions")

	spec, err := builder2.BuildOpenAPISpec(c.RegisteredWebServices(), oa.Config)
	if err != nil {
		klog.Fatalf("Failed to build open api spec for root: %v", err)
	}

	// we shadow ClustResourceQuotas, RoleBindingRestrictions, and SecurityContextContstraints
	// with a CRD. This loop removes all CRQ,RBR, SCC paths
	// from the OpenAPI spec such that they don't conflict with the CRD
	// apiextensions-apiserver spec during merging.
	for pth := range spec.Paths.Paths {
		if strings.HasPrefix(pth, "/apis/quota.openshift.io/v1/clusterresourcequotas") ||
			strings.Contains(pth, "rolebindingrestrictions") ||
			strings.HasPrefix(pth, "/apis/security.openshift.io/v1/securitycontextconstraints") {
			delete(spec.Paths.Paths, pth)
		}
	}

	spec.Definitions = handler.PruneDefaults(spec.Definitions)
	openAPIVersionedService, err := handler.NewOpenAPIService(spec)
	if err != nil {
		klog.Fatalf("Failed to create OpenAPIService: %v", err)
	}

	err = openAPIVersionedService.RegisterOpenAPIVersionedService("/openapi/v2", mux)
	if err != nil {
		klog.Fatalf("Failed to register versioned open api spec for root: %v", err)
	}

	return openAPIVersionedService, spec
}

// InstallV3 adds the static group/versions defined in the RegisteredWebServices to the OpenAPI v3 spec
func (oa OpenAPI) InstallV3(c *restful.Container, mux *mux.PathRecorderMux) *handler3.OpenAPIService {
	openAPIVersionedService, err := handler3.NewOpenAPIService(nil)
	if err != nil {
		klog.Fatalf("Failed to create OpenAPIService: %v", err)
	}

	err = openAPIVersionedService.RegisterOpenAPIV3VersionedService("/openapi/v3", mux)
	if err != nil {
		klog.Fatalf("Failed to register versioned open api spec for root: %v", err)
	}

	grouped := make(map[string][]*restful.WebService)

	for _, t := range c.RegisteredWebServices() {
		// Strip the "/" prefix from the name
		gvName := t.RootPath()[1:]
		grouped[gvName] = []*restful.WebService{t}
	}

	for gv, ws := range grouped {
		spec, err := builder3.BuildOpenAPISpec(ws, oa.Config)
		if err != nil {
			klog.Errorf("Failed to build OpenAPI v3 for group %s, %q", gv, err)

		}
		openAPIVersionedService.UpdateGroupVersion(gv, spec)
	}
	return openAPIVersionedService
}
<|endoftext|>


<commit_before>package log

import (
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

var _ LogWriter = &RollingFileAppender{}

func NewRollingFileAppender(file string, size int64, count int, async bool) *RollingFileAppender {
	this := new(RollingFileAppender)
	this.name, this.ext = splitNameExt(file)

	this.maxsize = size
	this.count = count

	// finds the last modified file to determine the current backup number
	log, err := filepath.Abs(file)
	if err != nil {
		panic(err)
	}
	folder := filepath.Dir(log)
	var maxtime time.Time
	var lastName string
	filepath.Walk(folder, func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() && strings.HasPrefix(info.Name(), this.name) && strings.HasSuffix(info.Name(), "."+this.ext) && info.ModTime().After(maxtime) {
			maxtime = info.ModTime()
			lastName = info.Name()
		}
		return nil
	})
	if lastName != "" {
		name, _ := splitNameExt(lastName)
		parts := strings.Split(name, COUNTER_SEP)
		this.currentCount, err = strconv.Atoi(parts[len(parts)-1])
		if err != nil {
			panic(err)
		}
		// check size of the current log
		finfo, err := os.Stat(lastName)
		if err == nil {
			this.written = finfo.Size()
		}
	}
	this.currentFilename = this.fullName()

	this.async = async
	return this
}

// split name and extension
func splitNameExt(file string) (string, string) {
	idx := strings.LastIndex(file, ".")
	if idx > 0 && idx < len(file)-1 {
		return file[:idx], file[idx+1:]
	} else {
		return file, ""
	}
}

/*
Roll the log file over a range of files once they go over the maxsize.
If maxsize == 0, then the log file will never rool.
If count == 0, then the backup log files will be infinite.
The format of the backup log files will be <name>-<counter>.<extension>
*/
type RollingFileAppender struct {
	name            string
	ext             string
	currentFilename string
	maxsize         int64
	written         int64
	count           int
	currentCount    int
	async           bool
}

// mark as AsyncLog
func (this *RollingFileAppender) IsAsync() bool {
	return this.async
}

func (this *RollingFileAppender) rollFile() {
	this.written = 0
	this.currentCount++
	if this.currentCount == this.count {
		this.currentCount = 0
	}
	this.currentFilename = this.fullName()
	os.Remove(this.currentFilename)
}

func (this *RollingFileAppender) fullName() string {
	name := this.name + COUNTER_SEP + strconv.Itoa(this.currentCount)
	if this.ext != "" {
		name += "." + this.ext
	}
	return name
}

func (this *RollingFileAppender) Write(p []byte) (n int, err error) {
	if this.maxsize > 0 && this.written > this.maxsize {
		this.rollFile()
	}

	fo, err := os.OpenFile(this.currentFilename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0)
	if err != nil {
		panic(err)
	}
	defer func() {
		if err := fo.Close(); err != nil {
			panic(err)
		}
	}()

	n, err = fo.Write(p)
	if this.maxsize > 0 {
		this.written += int64(n)
	}
	if err != nil {
		panic(err)
	}

	return n, nil
}
<commit_msg>fixed open file attributes<commit_after>package log

import (
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

var _ LogWriter = &RollingFileAppender{}

func NewRollingFileAppender(file string, size int64, count int, async bool) *RollingFileAppender {
	this := new(RollingFileAppender)
	this.name, this.ext = splitNameExt(file)

	this.maxsize = size
	this.count = count

	// finds the last modified file to determine the current backup number
	log, err := filepath.Abs(file)
	if err != nil {
		panic(err)
	}
	folder := filepath.Dir(log)
	var maxtime time.Time
	var lastName string
	filepath.Walk(folder, func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() && strings.HasPrefix(info.Name(), this.name) && strings.HasSuffix(info.Name(), "."+this.ext) && info.ModTime().After(maxtime) {
			maxtime = info.ModTime()
			lastName = info.Name()
		}
		return nil
	})
	if lastName != "" {
		name, _ := splitNameExt(lastName)
		parts := strings.Split(name, COUNTER_SEP)
		this.currentCount, err = strconv.Atoi(parts[len(parts)-1])
		if err != nil {
			panic(err)
		}
		// check size of the current log
		finfo, err := os.Stat(lastName)
		if err == nil {
			this.written = finfo.Size()
		}
	}
	this.currentFilename = this.fullName()

	this.async = async
	return this
}

// split name and extension
func splitNameExt(file string) (string, string) {
	idx := strings.LastIndex(file, ".")
	if idx > 0 && idx < len(file)-1 {
		return file[:idx], file[idx+1:]
	} else {
		return file, ""
	}
}

/*
Roll the log file over a range of files once they go over the maxsize.
If maxsize == 0, then the log file will never rool.
If count == 0, then the backup log files will be infinite.
The format of the backup log files will be <name>-<counter>.<extension>
*/
type RollingFileAppender struct {
	name            string
	ext             string
	currentFilename string
	maxsize         int64
	written         int64
	count           int
	currentCount    int
	async           bool
}

// mark as AsyncLog
func (this *RollingFileAppender) IsAsync() bool {
	return this.async
}

func (this *RollingFileAppender) rollFile() {
	this.written = 0
	this.currentCount++
	if this.currentCount == this.count {
		this.currentCount = 0
	}
	this.currentFilename = this.fullName()
	os.Remove(this.currentFilename)
}

func (this *RollingFileAppender) fullName() string {
	name := this.name + COUNTER_SEP + strconv.Itoa(this.currentCount)
	if this.ext != "" {
		name += "." + this.ext
	}
	return name
}

func (this *RollingFileAppender) Write(p []byte) (n int, err error) {
	if this.maxsize > 0 && this.written > this.maxsize {
		this.rollFile()
	}

	fo, err := os.OpenFile(this.currentFilename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		panic(err)
	}
	defer func() {
		if err := fo.Close(); err != nil {
			panic(err)
		}
	}()

	n, err = fo.Write(p)
	if this.maxsize > 0 {
		this.written += int64(n)
	}
	if err != nil {
		panic(err)
	}

	return n, nil
}
<|endoftext|>


<commit_before>/*
 * This file is a part of linuxdeploy - tool for
 * creating standalone applications for Linux
 *
 * Copyright (C) 2017 Taras Kushnir <kushnirTV@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the MIT License.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */

package main

import (
  "os"
  "os/exec"
  "log"
  "io"
  "path"
  "errors"
  "strings"
  "bytes"
)

func executablePath() string {
  fullpath, _ := exec.LookPath(os.Args[0])
  return fullpath
}

func copyFile(src, dst string) (err error) {
  in, err := os.Open(src)
  if err != nil {
    log.Printf("Failed to open source: %v", err)
    return
  }

  defer in.Close()

  out, err := os.Create(dst)
  if err != nil {
    log.Printf("Failed to create destination: %v", err)
    return
  }

  defer func() {
    cerr := out.Close()
    if err == nil {
      err = cerr
    }
  }()

  if _, err = io.Copy(out, in); err != nil {
    return
  }

  err = out.Sync()
  return
}

func ensureDirExists(fullpath string) (err error) {
  log.Printf("Ensure directory exists for file %v", fullpath)
  dirpath := path.Dir(fullpath)
  err = os.MkdirAll(dirpath, os.ModePerm)
  if err != nil {
    log.Printf("Failed to create directory %v", dirpath)
  }

  return err
}

func parseLddOutputLine(line string) (string, string, error) {
  if len(line) == 0 { return "", "", errors.New("Empty") }

  var libpath, libname string

  if strings.Contains(line, " => ") {
    parts := strings.Split(line, " => ")

    if len(parts) != 2 {
      return "", "", errors.New("Wrong format")
    }

    libname = strings.TrimSpace(parts[0])

    if parts[1] == "not found" { return parts[0], "", nil }

    lastUseful := strings.LastIndex(parts[1], "(0x")
    if lastUseful != -1 {
      libpath = strings.TrimSpace(parts[1][:lastUseful])
    }
  } else {
    log.Printf("Skipping ldd line: %v", line)
    return "", "", errors.New("Not with =>")
  }

  return libname, libpath, nil
}

func replaceInBuffer(buffer, key, replacement []byte) {
  index := bytes.Index(buffer, key)
  if index == -1 {
    log.Printf("Not found \"%s\" %v when replacing", key, key)
    return
  }

  nextIndex := len(key) + index
  log.Printf("Start of %s found at %v", key, nextIndex)

  endIndex := bytes.IndexByte(buffer[nextIndex:], byte(0))
  if endIndex == -1 {
    log.Printf("End not found for %s (%v) when replacing", key, key)
    return
  }

  log.Printf("Replacement End found at: %v", endIndex + nextIndex)

  if endIndex < len(replacement) {
    log.Printf("Cannot exceed length when replacing %s", key)
    return
  }

  i := nextIndex
  j := 0
  replacementSize := len(replacement)
  endIndex += nextIndex

  for (i < endIndex) && (j < replacementSize) {
    buffer[i] = replacement[j]
    j++
    i++
  }

  // pad with zeroes
  for i < endIndex {
    buffer[i] = byte(0)
    i++
  }

  log.Printf("Replaced \"%s\" %v to \"%s\" %v", key, key, replacement, replacement)
}

func replaceVariable(buffer []byte, varname, varvalue string) {
  replaceInBuffer(buffer, []byte(varname), []byte(varvalue))
}
<commit_msg>More logging for tests<commit_after>/*
 * This file is a part of linuxdeploy - tool for
 * creating standalone applications for Linux
 *
 * Copyright (C) 2017 Taras Kushnir <kushnirTV@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the MIT License.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */

package main

import (
  "os"
  "os/exec"
  "log"
  "io"
  "path"
  "errors"
  "strings"
  "bytes"
)

func executablePath() string {
  fullpath, _ := exec.LookPath(os.Args[0])
  return fullpath
}

func copyFile(src, dst string) (err error) {
  in, err := os.Open(src)
  if err != nil {
    log.Printf("Failed to open source: %v", err)
    return
  }

  defer in.Close()

  out, err := os.Create(dst)
  if err != nil {
    log.Printf("Failed to create destination: %v", err)
    return
  }

  defer func() {
    cerr := out.Close()
    if err == nil {
      err = cerr
    }
  }()

  if _, err = io.Copy(out, in); err != nil {
    return
  }

  err = out.Sync()
  return
}

func ensureDirExists(fullpath string) (err error) {
  log.Printf("Ensure directory exists for file %v", fullpath)
  dirpath := path.Dir(fullpath)
  err = os.MkdirAll(dirpath, os.ModePerm)
  if err != nil {
    log.Printf("Failed to create directory %v", dirpath)
  }

  return err
}

func parseLddOutputLine(line string) (string, string, error) {
  if len(line) == 0 { return "", "", errors.New("Empty") }

  var libpath, libname string

  if strings.Contains(line, " => ") {
    parts := strings.Split(line, " => ")

    if len(parts) != 2 {
      return "", "", errors.New("Wrong format")
    }

    libname = strings.TrimSpace(parts[0])

    if parts[1] == "not found" { return parts[0], "", nil }

    lastUseful := strings.LastIndex(parts[1], "(0x")
    if lastUseful != -1 {
      libpath = strings.TrimSpace(parts[1][:lastUseful])
    }
  } else {
    log.Printf("Skipping ldd line: %v", line)
    return "", "", errors.New("Not with =>")
  }

  return libname, libpath, nil
}

func replaceInBuffer(buffer, key, replacement []byte) {
  index := bytes.Index(buffer, key)
  if index == -1 {
    log.Printf("Not found \"%s\" %v when replacing", key, key)
    return
  }

  nextIndex := len(key) + index
  log.Printf("Start of %s found at %v", key, nextIndex)

  endIndex := bytes.IndexByte(buffer[nextIndex:], byte(0))
  if endIndex == -1 {
    log.Printf("End not found for %s (%v) when replacing", key, key)
    return
  }

  log.Printf("Replacement End found at %v", endIndex + nextIndex)

  if endIndex < len(replacement) {
    log.Printf("Cannot exceed length when replacing %s", key)
    return
  }

  i := nextIndex
  j := 0
  replacementSize := len(replacement)
  endIndex += nextIndex

  log.Printf("Replacement previous value is %s", buffer[nextIndex:endIndex])

  for (i < endIndex) && (j < replacementSize) {
    buffer[i] = replacement[j]
    j++
    i++
  }

  // pad with zeroes
  for i < endIndex {
    buffer[i] = byte(0)
    i++
  }

  log.Printf("Replaced \"%s\" %v to \"%s\" %v", key, key, replacement, replacement)
}

func replaceVariable(buffer []byte, varname, varvalue string) {
  replaceInBuffer(buffer, []byte(varname), []byte(varvalue))
}
<|endoftext|>


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

// Package pe implements access to PE (Microsoft Windows Portable Executable) files.
package pe

import (
	"debug/dwarf"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"os"
)

// A File represents an open PE file.
type File struct {
	FileHeader
	OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64
	Sections       []*Section
	Symbols        []*Symbol    // COFF symbols with auxiliary symbol records removed
	COFFSymbols    []COFFSymbol // all COFF symbols (including auxiliary symbol records)
	StringTable    StringTable

	closer io.Closer
}

// Open opens the named file using os.Open and prepares it for use as a PE binary.
func Open(name string) (*File, error) {
	f, err := os.Open(name)
	if err != nil {
		return nil, err
	}
	ff, err := NewFile(f)
	if err != nil {
		f.Close()
		return nil, err
	}
	ff.closer = f
	return ff, nil
}

// Close closes the File.
// If the File was created using NewFile directly instead of Open,
// Close has no effect.
func (f *File) Close() error {
	var err error
	if f.closer != nil {
		err = f.closer.Close()
		f.closer = nil
	}
	return err
}

var (
	sizeofOptionalHeader32 = uint16(binary.Size(OptionalHeader32{}))
	sizeofOptionalHeader64 = uint16(binary.Size(OptionalHeader64{}))
)

// NewFile creates a new File for accessing a PE binary in an underlying reader.
func NewFile(r io.ReaderAt) (*File, error) {
	f := new(File)
	sr := io.NewSectionReader(r, 0, 1<<63-1)

	var dosheader [96]byte
	if _, err := r.ReadAt(dosheader[0:], 0); err != nil {
		return nil, err
	}
	var base int64
	if dosheader[0] == 'M' && dosheader[1] == 'Z' {
		signoff := int64(binary.LittleEndian.Uint32(dosheader[0x3c:]))
		var sign [4]byte
		r.ReadAt(sign[:], signoff)
		if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) {
			return nil, errors.New("Invalid PE File Format.")
		}
		base = signoff + 4
	} else {
		base = int64(0)
	}
	sr.Seek(base, io.SeekStart)
	if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
		return nil, err
	}
	if f.FileHeader.Machine != IMAGE_FILE_MACHINE_UNKNOWN && f.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 && f.FileHeader.Machine != IMAGE_FILE_MACHINE_I386 {
		return nil, errors.New("Invalid PE File Format.")
	}

	var err error

	// Read string table.
	f.StringTable, err = readStringTable(&f.FileHeader, sr)
	if err != nil {
		return nil, err
	}

	// Read symbol table.
	f.COFFSymbols, err = readCOFFSymbols(&f.FileHeader, sr)
	if err != nil {
		return nil, err
	}
	f.Symbols, err = removeAuxSymbols(f.COFFSymbols, f.StringTable)
	if err != nil {
		return nil, err
	}

	// Read optional header.
	sr.Seek(base, io.SeekStart)
	if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
		return nil, err
	}
	var oh32 OptionalHeader32
	var oh64 OptionalHeader64
	switch f.FileHeader.SizeOfOptionalHeader {
	case sizeofOptionalHeader32:
		if err := binary.Read(sr, binary.LittleEndian, &oh32); err != nil {
			return nil, err
		}
		if oh32.Magic != 0x10b { // PE32
			return nil, fmt.Errorf("pe32 optional header has unexpected Magic of 0x%x", oh32.Magic)
		}
		f.OptionalHeader = &oh32
	case sizeofOptionalHeader64:
		if err := binary.Read(sr, binary.LittleEndian, &oh64); err != nil {
			return nil, err
		}
		if oh64.Magic != 0x20b { // PE32+
			return nil, fmt.Errorf("pe32+ optional header has unexpected Magic of 0x%x", oh64.Magic)
		}
		f.OptionalHeader = &oh64
	}

	// Process sections.
	f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
	for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
		sh := new(SectionHeader32)
		if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
			return nil, err
		}
		name, err := sh.fullName(f.StringTable)
		if err != nil {
			return nil, err
		}
		s := new(Section)
		s.SectionHeader = SectionHeader{
			Name:                 name,
			VirtualSize:          sh.VirtualSize,
			VirtualAddress:       sh.VirtualAddress,
			Size:                 sh.SizeOfRawData,
			Offset:               sh.PointerToRawData,
			PointerToRelocations: sh.PointerToRelocations,
			PointerToLineNumbers: sh.PointerToLineNumbers,
			NumberOfRelocations:  sh.NumberOfRelocations,
			NumberOfLineNumbers:  sh.NumberOfLineNumbers,
			Characteristics:      sh.Characteristics,
		}
		s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
		s.ReaderAt = s.sr
		f.Sections[i] = s
	}
	for i := range f.Sections {
		var err error
		f.Sections[i].Relocs, err = readRelocs(&f.Sections[i].SectionHeader, sr)
		if err != nil {
			return nil, err
		}
	}

	return f, nil
}

// getString extracts a string from symbol string table.
func getString(section []byte, start int) (string, bool) {
	if start < 0 || start >= len(section) {
		return "", false
	}

	for end := start; end < len(section); end++ {
		if section[end] == 0 {
			return string(section[start:end]), true
		}
	}
	return "", false
}

// Section returns the first section with the given name, or nil if no such
// section exists.
func (f *File) Section(name string) *Section {
	for _, s := range f.Sections {
		if s.Name == name {
			return s
		}
	}
	return nil
}

func (f *File) DWARF() (*dwarf.Data, error) {
	// There are many other DWARF sections, but these
	// are the ones the debug/dwarf package uses.
	// Don't bother loading others.
	var names = [...]string{"abbrev", "info", "line", "ranges", "str"}
	var dat [len(names)][]byte
	for i, name := range names {
		name = ".debug_" + name
		s := f.Section(name)
		if s == nil {
			continue
		}
		b, err := s.Data()
		if err != nil && uint32(len(b)) < s.Size {
			return nil, err
		}
		if 0 < s.VirtualSize && s.VirtualSize < s.Size {
			b = b[:s.VirtualSize]
		}
		dat[i] = b
	}

	abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
	return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
}

// TODO(brainman): document ImportDirectory once we decide what to do with it.

type ImportDirectory struct {
	OriginalFirstThunk uint32
	TimeDateStamp      uint32
	ForwarderChain     uint32
	Name               uint32
	FirstThunk         uint32

	dll string
}

// ImportedSymbols returns the names of all symbols
// referred to by the binary f that are expected to be
// satisfied by other libraries at dynamic load time.
// It does not return weak symbols.
func (f *File) ImportedSymbols() ([]string, error) {
	pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64
	ds := f.Section(".idata")
	if ds == nil {
		// not dynamic, so no libraries
		return nil, nil
	}
	d, err := ds.Data()
	if err != nil {
		return nil, err
	}
	var ida []ImportDirectory
	for len(d) > 0 {
		var dt ImportDirectory
		dt.OriginalFirstThunk = binary.LittleEndian.Uint32(d[0:4])
		dt.Name = binary.LittleEndian.Uint32(d[12:16])
		dt.FirstThunk = binary.LittleEndian.Uint32(d[16:20])
		d = d[20:]
		if dt.OriginalFirstThunk == 0 {
			break
		}
		ida = append(ida, dt)
	}
	// TODO(brainman): this needs to be rewritten
	//  ds.Data() return contets of .idata section. Why store in variable called "names"?
	//  Why we are retrieving it second time? We already have it in "d", and it is not modified anywhere.
	//  getString does not extracts a string from symbol string table (as getString doco says).
	//  Why ds.Data() called again and again in the loop?
	//  Needs test before rewrite.
	names, _ := ds.Data()
	var all []string
	for _, dt := range ida {
		dt.dll, _ = getString(names, int(dt.Name-ds.VirtualAddress))
		d, _ = ds.Data()
		// seek to OriginalFirstThunk
		d = d[dt.OriginalFirstThunk-ds.VirtualAddress:]
		for len(d) > 0 {
			if pe64 { // 64bit
				va := binary.LittleEndian.Uint64(d[0:8])
				d = d[8:]
				if va == 0 {
					break
				}
				if va&0x8000000000000000 > 0 { // is Ordinal
					// TODO add dynimport ordinal support.
				} else {
					fn, _ := getString(names, int(uint32(va)-ds.VirtualAddress+2))
					all = append(all, fn+":"+dt.dll)
				}
			} else { // 32bit
				va := binary.LittleEndian.Uint32(d[0:4])
				d = d[4:]
				if va == 0 {
					break
				}
				if va&0x80000000 > 0 { // is Ordinal
					// TODO add dynimport ordinal support.
					//ord := va&0x0000FFFF
				} else {
					fn, _ := getString(names, int(va-ds.VirtualAddress+2))
					all = append(all, fn+":"+dt.dll)
				}
			}
		}
	}

	return all, nil
}

// ImportedLibraries returns the names of all libraries
// referred to by the binary f that are expected to be
// linked with the binary at dynamic link time.
func (f *File) ImportedLibraries() ([]string, error) {
	// TODO
	// cgo -dynimport don't use this for windows PE, so just return.
	return nil, nil
}

// FormatError is unused.
// The type is retained for compatibility.
type FormatError struct {
}

func (e *FormatError) Error() string {
	return "unknown error"
}
<commit_msg>debug/pe: better error messages<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package pe implements access to PE (Microsoft Windows Portable Executable) files.
package pe

import (
	"debug/dwarf"
	"encoding/binary"
	"fmt"
	"io"
	"os"
)

// A File represents an open PE file.
type File struct {
	FileHeader
	OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64
	Sections       []*Section
	Symbols        []*Symbol    // COFF symbols with auxiliary symbol records removed
	COFFSymbols    []COFFSymbol // all COFF symbols (including auxiliary symbol records)
	StringTable    StringTable

	closer io.Closer
}

// Open opens the named file using os.Open and prepares it for use as a PE binary.
func Open(name string) (*File, error) {
	f, err := os.Open(name)
	if err != nil {
		return nil, err
	}
	ff, err := NewFile(f)
	if err != nil {
		f.Close()
		return nil, err
	}
	ff.closer = f
	return ff, nil
}

// Close closes the File.
// If the File was created using NewFile directly instead of Open,
// Close has no effect.
func (f *File) Close() error {
	var err error
	if f.closer != nil {
		err = f.closer.Close()
		f.closer = nil
	}
	return err
}

var (
	sizeofOptionalHeader32 = uint16(binary.Size(OptionalHeader32{}))
	sizeofOptionalHeader64 = uint16(binary.Size(OptionalHeader64{}))
)

// TODO(brainman): add Load function, as a replacement for NewFile, that does not call removeAuxSymbols (for performance)

// NewFile creates a new File for accessing a PE binary in an underlying reader.
func NewFile(r io.ReaderAt) (*File, error) {
	f := new(File)
	sr := io.NewSectionReader(r, 0, 1<<63-1)

	var dosheader [96]byte
	if _, err := r.ReadAt(dosheader[0:], 0); err != nil {
		return nil, err
	}
	var base int64
	if dosheader[0] == 'M' && dosheader[1] == 'Z' {
		signoff := int64(binary.LittleEndian.Uint32(dosheader[0x3c:]))
		var sign [4]byte
		r.ReadAt(sign[:], signoff)
		if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) {
			return nil, fmt.Errorf("Invalid PE COFF file signature of %v.", sign)
		}
		base = signoff + 4
	} else {
		base = int64(0)
	}
	sr.Seek(base, io.SeekStart)
	if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
		return nil, err
	}
	switch f.FileHeader.Machine {
	case IMAGE_FILE_MACHINE_UNKNOWN, IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386:
	default:
		return nil, fmt.Errorf("Unrecognised COFF file header machine value of 0x%x.", f.FileHeader.Machine)
	}

	var err error

	// Read string table.
	f.StringTable, err = readStringTable(&f.FileHeader, sr)
	if err != nil {
		return nil, err
	}

	// Read symbol table.
	f.COFFSymbols, err = readCOFFSymbols(&f.FileHeader, sr)
	if err != nil {
		return nil, err
	}
	f.Symbols, err = removeAuxSymbols(f.COFFSymbols, f.StringTable)
	if err != nil {
		return nil, err
	}

	// Read optional header.
	sr.Seek(base, io.SeekStart)
	if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
		return nil, err
	}
	var oh32 OptionalHeader32
	var oh64 OptionalHeader64
	switch f.FileHeader.SizeOfOptionalHeader {
	case sizeofOptionalHeader32:
		if err := binary.Read(sr, binary.LittleEndian, &oh32); err != nil {
			return nil, err
		}
		if oh32.Magic != 0x10b { // PE32
			return nil, fmt.Errorf("pe32 optional header has unexpected Magic of 0x%x", oh32.Magic)
		}
		f.OptionalHeader = &oh32
	case sizeofOptionalHeader64:
		if err := binary.Read(sr, binary.LittleEndian, &oh64); err != nil {
			return nil, err
		}
		if oh64.Magic != 0x20b { // PE32+
			return nil, fmt.Errorf("pe32+ optional header has unexpected Magic of 0x%x", oh64.Magic)
		}
		f.OptionalHeader = &oh64
	}

	// Process sections.
	f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
	for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
		sh := new(SectionHeader32)
		if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
			return nil, err
		}
		name, err := sh.fullName(f.StringTable)
		if err != nil {
			return nil, err
		}
		s := new(Section)
		s.SectionHeader = SectionHeader{
			Name:                 name,
			VirtualSize:          sh.VirtualSize,
			VirtualAddress:       sh.VirtualAddress,
			Size:                 sh.SizeOfRawData,
			Offset:               sh.PointerToRawData,
			PointerToRelocations: sh.PointerToRelocations,
			PointerToLineNumbers: sh.PointerToLineNumbers,
			NumberOfRelocations:  sh.NumberOfRelocations,
			NumberOfLineNumbers:  sh.NumberOfLineNumbers,
			Characteristics:      sh.Characteristics,
		}
		s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
		s.ReaderAt = s.sr
		f.Sections[i] = s
	}
	for i := range f.Sections {
		var err error
		f.Sections[i].Relocs, err = readRelocs(&f.Sections[i].SectionHeader, sr)
		if err != nil {
			return nil, err
		}
	}

	return f, nil
}

// getString extracts a string from symbol string table.
func getString(section []byte, start int) (string, bool) {
	if start < 0 || start >= len(section) {
		return "", false
	}

	for end := start; end < len(section); end++ {
		if section[end] == 0 {
			return string(section[start:end]), true
		}
	}
	return "", false
}

// Section returns the first section with the given name, or nil if no such
// section exists.
func (f *File) Section(name string) *Section {
	for _, s := range f.Sections {
		if s.Name == name {
			return s
		}
	}
	return nil
}

func (f *File) DWARF() (*dwarf.Data, error) {
	// There are many other DWARF sections, but these
	// are the ones the debug/dwarf package uses.
	// Don't bother loading others.
	var names = [...]string{"abbrev", "info", "line", "ranges", "str"}
	var dat [len(names)][]byte
	for i, name := range names {
		name = ".debug_" + name
		s := f.Section(name)
		if s == nil {
			continue
		}
		b, err := s.Data()
		if err != nil && uint32(len(b)) < s.Size {
			return nil, err
		}
		if 0 < s.VirtualSize && s.VirtualSize < s.Size {
			b = b[:s.VirtualSize]
		}
		dat[i] = b
	}

	abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
	return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
}

// TODO(brainman): document ImportDirectory once we decide what to do with it.

type ImportDirectory struct {
	OriginalFirstThunk uint32
	TimeDateStamp      uint32
	ForwarderChain     uint32
	Name               uint32
	FirstThunk         uint32

	dll string
}

// ImportedSymbols returns the names of all symbols
// referred to by the binary f that are expected to be
// satisfied by other libraries at dynamic load time.
// It does not return weak symbols.
func (f *File) ImportedSymbols() ([]string, error) {
	pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64
	ds := f.Section(".idata")
	if ds == nil {
		// not dynamic, so no libraries
		return nil, nil
	}
	d, err := ds.Data()
	if err != nil {
		return nil, err
	}
	var ida []ImportDirectory
	for len(d) > 0 {
		var dt ImportDirectory
		dt.OriginalFirstThunk = binary.LittleEndian.Uint32(d[0:4])
		dt.Name = binary.LittleEndian.Uint32(d[12:16])
		dt.FirstThunk = binary.LittleEndian.Uint32(d[16:20])
		d = d[20:]
		if dt.OriginalFirstThunk == 0 {
			break
		}
		ida = append(ida, dt)
	}
	// TODO(brainman): this needs to be rewritten
	//  ds.Data() return contets of .idata section. Why store in variable called "names"?
	//  Why we are retrieving it second time? We already have it in "d", and it is not modified anywhere.
	//  getString does not extracts a string from symbol string table (as getString doco says).
	//  Why ds.Data() called again and again in the loop?
	//  Needs test before rewrite.
	names, _ := ds.Data()
	var all []string
	for _, dt := range ida {
		dt.dll, _ = getString(names, int(dt.Name-ds.VirtualAddress))
		d, _ = ds.Data()
		// seek to OriginalFirstThunk
		d = d[dt.OriginalFirstThunk-ds.VirtualAddress:]
		for len(d) > 0 {
			if pe64 { // 64bit
				va := binary.LittleEndian.Uint64(d[0:8])
				d = d[8:]
				if va == 0 {
					break
				}
				if va&0x8000000000000000 > 0 { // is Ordinal
					// TODO add dynimport ordinal support.
				} else {
					fn, _ := getString(names, int(uint32(va)-ds.VirtualAddress+2))
					all = append(all, fn+":"+dt.dll)
				}
			} else { // 32bit
				va := binary.LittleEndian.Uint32(d[0:4])
				d = d[4:]
				if va == 0 {
					break
				}
				if va&0x80000000 > 0 { // is Ordinal
					// TODO add dynimport ordinal support.
					//ord := va&0x0000FFFF
				} else {
					fn, _ := getString(names, int(va-ds.VirtualAddress+2))
					all = append(all, fn+":"+dt.dll)
				}
			}
		}
	}

	return all, nil
}

// ImportedLibraries returns the names of all libraries
// referred to by the binary f that are expected to be
// linked with the binary at dynamic link time.
func (f *File) ImportedLibraries() ([]string, error) {
	// TODO
	// cgo -dynimport don't use this for windows PE, so just return.
	return nil, nil
}

// FormatError is unused.
// The type is retained for compatibility.
type FormatError struct {
}

func (e *FormatError) Error() string {
	return "unknown error"
}
<|endoftext|>


<commit_before>package controller

import (
	"errors"
	"encoding/json"
	"net/http"
	"app/model"
	"github.com/julienschmidt/httprouter"
	"gopkg.in/go-playground/validator.v9"
)

type Success struct {
	Success string `json: "success"`
	User []model.User `json: "user"`
}

type Error struct {
	Err string `json: "error"`
	User []model.User `json: "user"`
}

var validate *validator.Validate

func validateUser(user model.User) error {
	var error string
	vErr := validate.Struct(user)
	if vErr != nil {
		for _, err := range vErr.(validator.ValidationErrors) {
			error += ", "
			if err.Tag() == "required" {
				error += err.Field() + ": is required "
			}
			if err.Tag() == "alphanum"|| err.Tag() == "excludesall" {
				error += err.Field() + ": constains invalid characters "
			}
			if err.Tag() == "gt" {
				var gt string
				if err.Field() == "Name" {
					gt = model.GtName
				} else {
					gt = model.GtPassword
				}
				error += err.Field() + ": must have more than " + gt + " characters"
			}
		}
		rErr := errors.New(error)
		return rErr
	} else {
		return nil
	}
}

func UserPOST(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	validate = validator.New()
	w.Header().Set("Content-Type", "application/json")
	name, password := r.FormValue("name"), r.FormValue("password")
	user := model.User{name, password}
	vErr := validateUser(user)
	ex := model.UserCreate(name, password)
	var jData []byte
	if vErr != nil {
		e := vErr.Error()
		response := &Error {
			Err: e,
			User: []model.User{user}}
		jData, _ = json.Marshal(response)
	} else if ex != nil {
		s := ex.Error()
		response := &Error{
			Err: s,
			User: []model.User{user}}
		jData, _ = json.Marshal(response)
	} else {
		response := &Success{
			Success: "user created",
			User: []model.User{user}}
		jData, _ = json.Marshal(response)
	}
	w.Write(jData)
}
<commit_msg>correcting miss typing issues;<commit_after>package controller

import (
	"errors"
	"encoding/json"
	"net/http"
	"app/model"
	"github.com/julienschmidt/httprouter"
	"gopkg.in/go-playground/validator.v9"
)

type Success struct {
	Success string `json: "success"`
	User []model.User `json: "user"`
}

type Error struct {
	Err string `json: "error"`
	User []model.User `json: "user"`
}

var validate *validator.Validate

func validateUser(user model.User) error {
	var error string
	vErr := validate.Struct(user)
	if vErr != nil {
		for _, err := range vErr.(validator.ValidationErrors) {
			error += ", "
			if err.Tag() == "required" {
				error += err.Field() + ": is required "
			}
			if err.Tag() == "alphanum" || err.Tag() == "excludesall" {
				error += err.Field() + ": contains invalid characters "
			}
			if err.Tag() == "gt" {
				var gt string
				if err.Field() == "Name" {
					gt = model.GtName
				} else {
					gt = model.GtPassword
				}
				error += err.Field() + ": must have more than " + gt + " characters"
			}
		}
		rErr := errors.New(error)
		return rErr
	} else {
		return nil
	}
}

func UserPOST(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	validate = validator.New()
	w.Header().Set("Content-Type", "application/json")
	name, password := r.FormValue("name"), r.FormValue("password")
	user := model.User{name, password}
	vErr := validateUser(user)
	ex := model.UserCreate(name, password)
	var jData []byte
	if vErr != nil {
		e := vErr.Error()
		response := &Error {
			Err: e,
			User: []model.User{user}}
		jData, _ = json.Marshal(response)
	} else if ex != nil {
		s := ex.Error()
		response := &Error{
			Err: s,
			User: []model.User{user}}
		jData, _ = json.Marshal(response)
	} else {
		response := &Success{
			Success: "user_create",
			User: []model.User{user}}
		jData, _ = json.Marshal(response)
	}
	w.Write(jData)
}
<|endoftext|>