github.com/StackExchange/blackbox/v2@v2.0.1-0.20220331193400-d84e904973ab/pkg/bbutil/shred.go (about)

     1  package bbutil
     2  
     3  // Pick an appropriate secure erase command for this operating system
     4  // or just delete the file with os.Remove().
     5  
     6  // Code rewritten based https://codereview.stackexchange.com/questions/245072
     7  
     8  import (
     9  	"fmt"
    10  	"io/ioutil"
    11  	"os"
    12  	"os/exec"
    13  )
    14  
    15  var shredCmds = []struct {
    16  	name, opts string
    17  }{
    18  	{"sdelete", "-a"},
    19  	{"shred", "-u"},
    20  	{"srm", "-f"},
    21  	{"rm", "-Pf"},
    22  }
    23  
    24  func shredTemp(path, opts string) error {
    25  	file, err := ioutil.TempFile("", "shredTemp.")
    26  	if err != nil {
    27  		return err
    28  	}
    29  	filename := file.Name()
    30  	defer os.Remove(filename)
    31  	defer file.Close()
    32  
    33  	err = file.Close()
    34  	if err != nil {
    35  		return err
    36  	}
    37  	err = RunBash(path, opts, filename)
    38  	if err != nil {
    39  		return err
    40  	}
    41  	return nil
    42  }
    43  
    44  var shredPath, shredOpts = func() (string, string) {
    45  	for _, cmd := range shredCmds {
    46  		path, err := exec.LookPath(cmd.name)
    47  		if err != nil {
    48  			continue
    49  		}
    50  		err = shredTemp(path, cmd.opts)
    51  		if err == nil {
    52  			return path, cmd.opts
    53  		}
    54  	}
    55  	return "", ""
    56  }()
    57  
    58  // ShredInfo reveals the shred command and flags (for "blackbox info")
    59  func ShredInfo() string {
    60  	return shredPath + " " + shredOpts
    61  }
    62  
    63  // shredFile shreds one file.
    64  func shredFile(filename string) error {
    65  	fi, err := os.Stat(filename)
    66  	if err != nil {
    67  		return err
    68  	}
    69  	if !fi.Mode().IsRegular() {
    70  		err := fmt.Errorf("filename is not mode regular")
    71  		return err
    72  	}
    73  
    74  	if shredPath == "" {
    75  		// No secure erase command found.  Default to a normal file delete.
    76  		// TODO(tlim): Print a warning? Have a flag that causes this to be an error?
    77  		return os.Remove(filename)
    78  	}
    79  
    80  	err = RunBash(shredPath, shredOpts, filename)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	return nil
    85  }
    86  
    87  // ShredFiles securely erases a list of files.
    88  func ShredFiles(names []string) error {
    89  
    90  	// TODO(tlim) DO the shredding in parallel like in v1.
    91  
    92  	var eerr error
    93  	for _, n := range names {
    94  		_, err := os.Stat(n)
    95  		if err != nil {
    96  			if os.IsNotExist(err) {
    97  				fmt.Printf("======= already gone: %q\n", n)
    98  				continue
    99  			}
   100  		}
   101  		fmt.Printf("========== SHREDDING: %q\n", n)
   102  		e := shredFile(n)
   103  		if e != nil {
   104  			eerr = e
   105  			fmt.Printf("ERROR: %v\n", e)
   106  		}
   107  	}
   108  	return eerr
   109  }