github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/core/truncate/truncate.go (about)

     1  // Copyright 2013-2017 the u-root 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  // Truncate - shrink or extend the size of a file to the specified size
     6  //
     7  // Synopsis:
     8  //
     9  //	truncate [OPTIONS] [FILE]...
    10  //
    11  // Options:
    12  //
    13  //	-s: size in bytes
    14  //	-r: reference file for size
    15  //	-c: do not create any files
    16  //
    17  // Author:
    18  //
    19  //	Roland Kammerer <dev.rck@gmail.com>
    20  package main
    21  
    22  import (
    23  	"flag"
    24  	"fmt"
    25  	"log"
    26  	"os"
    27  
    28  	"github.com/rck/unit"
    29  	"github.com/mvdan/u-root-coreutils/pkg/uroot/util"
    30  )
    31  
    32  const usage = "truncate [-c] -s size file..."
    33  
    34  var (
    35  	create = flag.Bool("c", false, "Do not create files.")
    36  	size   = unit.MustNewUnit(unit.DefaultUnits).MustNewValue(1, unit.None)
    37  	rfile  = flag.String("r", "", "Reference file for size")
    38  )
    39  
    40  func init() {
    41  	flag.Var(size, "s", "Size in bytes, prefixes +/- are allowed")
    42  	flag.Usage = util.Usage(flag.Usage, usage)
    43  }
    44  
    45  func truncate(args ...string) error {
    46  	if !size.IsSet && *rfile == "" {
    47  		return fmt.Errorf("you need to specify size via -s <number> or -r <rfile>")
    48  	}
    49  	if size.IsSet && *rfile != "" {
    50  		return fmt.Errorf("you need to specify size via -s <number> or -r <rfile>")
    51  	}
    52  	if len(args) == 0 {
    53  		return fmt.Errorf("you need to specify one or more files as argument")
    54  	}
    55  
    56  	for _, fname := range args {
    57  
    58  		var final int64
    59  		st, err := os.Stat(fname)
    60  		if os.IsNotExist(err) && !*create {
    61  			if err = os.WriteFile(fname, []byte{}, 0o644); err != nil {
    62  				return fmt.Errorf("%v", err)
    63  			}
    64  			if st, err = os.Stat(fname); err != nil {
    65  				return fmt.Errorf("could not stat newly created file: %v", err)
    66  			}
    67  		}
    68  		if *rfile != "" {
    69  			if st, err = os.Stat(*rfile); err != nil {
    70  				return fmt.Errorf("could not stat reference file: %v", err)
    71  			}
    72  			final = st.Size()
    73  		} else if size.IsSet {
    74  			final = size.Value // base case
    75  			if size.ExplicitSign != unit.None {
    76  				final += st.Size() // in case of '-', size.Value is already negative
    77  			}
    78  			if final < 0 {
    79  				final = 0
    80  			}
    81  		}
    82  
    83  		// intentionally ignore, like GNU truncate
    84  		os.Truncate(fname, final)
    85  	}
    86  	return nil
    87  }
    88  
    89  func main() {
    90  	flag.Parse()
    91  	if err := truncate(flag.Args()...); err != nil {
    92  		flag.Usage()
    93  		log.Fatal(err)
    94  	}
    95  }