...

Source file src/golang.org/x/tools/cmd/file2fuzz/main.go

Documentation: golang.org/x/tools/cmd/file2fuzz

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // file2fuzz converts binary files, such as those used by go-fuzz, to the Go
     6  // fuzzing corpus format.
     7  //
     8  // Usage:
     9  //
    10  //	file2fuzz [-o output] [input...]
    11  //
    12  // The default behavior is to read input from stdin and write the converted
    13  // output to stdout. If any position arguments are provided stdin is ignored
    14  // and the arguments are assumed to be input files to convert.
    15  //
    16  // The -o flag provides an path to write output files to. If only one positional
    17  // argument is specified it may be a file path or an existing directory, if there are
    18  // multiple inputs specified it must be a directory. If a directory is provided
    19  // the name of the file will be the SHA-256 hash of its contents.
    20  package main
    21  
    22  import (
    23  	"crypto/sha256"
    24  	"errors"
    25  	"flag"
    26  	"fmt"
    27  	"io"
    28  	"log"
    29  	"os"
    30  	"path/filepath"
    31  )
    32  
    33  // encVersion1 is version 1 Go fuzzer corpus encoding.
    34  var encVersion1 = "go test fuzz v1"
    35  
    36  func encodeByteSlice(b []byte) []byte {
    37  	return []byte(fmt.Sprintf("%s\n[]byte(%q)", encVersion1, b))
    38  }
    39  
    40  func usage() {
    41  	fmt.Fprintf(os.Stderr, "usage: file2fuzz [-o output] [input...]\nconverts files to Go fuzzer corpus format\n")
    42  	fmt.Fprintf(os.Stderr, "\tinput: files to convert\n")
    43  	fmt.Fprintf(os.Stderr, "\t-o: where to write converted file(s)\n")
    44  	os.Exit(2)
    45  }
    46  func dirWriter(dir string) func([]byte) error {
    47  	return func(b []byte) error {
    48  		sum := fmt.Sprintf("%x", sha256.Sum256(b))
    49  		name := filepath.Join(dir, sum)
    50  		if err := os.MkdirAll(dir, 0777); err != nil {
    51  			return err
    52  		}
    53  		if err := os.WriteFile(name, b, 0666); err != nil {
    54  			os.Remove(name)
    55  			return err
    56  		}
    57  		return nil
    58  	}
    59  }
    60  
    61  func convert(inputArgs []string, outputArg string) error {
    62  	var input []io.Reader
    63  	if args := inputArgs; len(args) == 0 {
    64  		input = []io.Reader{os.Stdin}
    65  	} else {
    66  		for _, a := range args {
    67  			f, err := os.Open(a)
    68  			if err != nil {
    69  				return fmt.Errorf("unable to open %q: %s", a, err)
    70  			}
    71  			defer f.Close()
    72  			if fi, err := f.Stat(); err != nil {
    73  				return fmt.Errorf("unable to open %q: %s", a, err)
    74  			} else if fi.IsDir() {
    75  				return fmt.Errorf("%q is a directory, not a file", a)
    76  			}
    77  			input = append(input, f)
    78  		}
    79  	}
    80  
    81  	var output func([]byte) error
    82  	if outputArg == "" {
    83  		if len(inputArgs) > 1 {
    84  			return errors.New("-o required with multiple input files")
    85  		}
    86  		output = func(b []byte) error {
    87  			_, err := os.Stdout.Write(b)
    88  			return err
    89  		}
    90  	} else {
    91  		if len(inputArgs) > 1 {
    92  			output = dirWriter(outputArg)
    93  		} else {
    94  			if fi, err := os.Stat(outputArg); err != nil && !os.IsNotExist(err) {
    95  				return fmt.Errorf("unable to open %q for writing: %s", outputArg, err)
    96  			} else if err == nil && fi.IsDir() {
    97  				output = dirWriter(outputArg)
    98  			} else {
    99  				output = func(b []byte) error {
   100  					return os.WriteFile(outputArg, b, 0666)
   101  				}
   102  			}
   103  		}
   104  	}
   105  
   106  	for _, f := range input {
   107  		b, err := io.ReadAll(f)
   108  		if err != nil {
   109  			return fmt.Errorf("unable to read input: %s", err)
   110  		}
   111  		if err := output(encodeByteSlice(b)); err != nil {
   112  			return fmt.Errorf("unable to write output: %s", err)
   113  		}
   114  	}
   115  
   116  	return nil
   117  }
   118  
   119  func main() {
   120  	log.SetFlags(0)
   121  	log.SetPrefix("file2fuzz: ")
   122  
   123  	output := flag.String("o", "", "where to write converted file(s)")
   124  	flag.Usage = usage
   125  	flag.Parse()
   126  
   127  	if err := convert(flag.Args(), *output); err != nil {
   128  		log.Fatal(err)
   129  	}
   130  }
   131  

View as plain text