Skip to content

Commit

Permalink
Make Wipe() wipe partitions, Add demo disk wipe.
Browse files Browse the repository at this point in the history
Previously, system.Wipe() would only wipe the first and last MiB
of the disk.  Now, it will also wipe the first and last MiB of
any partitions on the disk.

Also, add 'demo disk wipe' subcommand that calls this.
  • Loading branch information
Scott Moser committed Sep 10, 2020
1 parent a6d85b9 commit 8b51eb3
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 33 deletions.
49 changes: 32 additions & 17 deletions demo/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ var diskCommands = cli.Command{
Usage: "Scan disks on the system and dump data (human)",
Action: diskShow,
},
{
Name: "wipe",
Usage: ("Quickly wipe disks on the system. Zero any existing " +
"beginning and end of disk and any existing partitions"),
Action: diskWipe,
},
},
}

Expand All @@ -43,6 +49,7 @@ func diskScan(c *cli.Context) error {
}

if c.Args().Len() == 1 {
// a single argument will only output 1 disk, not an array of one disk.
disk, err := mysys.ScanDisk(c.Args().First())
if err != nil {
return err
Expand Down Expand Up @@ -78,37 +85,45 @@ func diskScan(c *cli.Context) error {
}

func diskShow(c *cli.Context) error {
var err error

mysys := linux.System()
matchAll := func(d disko.Disk) bool {
return true
disks, err := getDiskSet(mysys, c.Args().Slice()...)

if err != nil {
return err
}

if c.Args().Len() == 1 {
disk, err := mysys.ScanDisk(c.Args().First())
if err != nil {
return err
}
for _, d := range disks {
fmt.Printf("%s\n%s\n", d.String(), d.Details())
}

fmt.Printf("%s\n%s\n", disk.String(), disk.Details())
return nil
}

return nil
func getDiskSet(mysys disko.System, paths ...string) (disko.DiskSet, error) {
matchAll := func(d disko.Disk) bool {
return true
}

var disks disko.DiskSet
if c.Args().Len() == 0 {
disks, err = mysys.ScanAllDisks(matchAll)
} else {
disks, err = mysys.ScanDisks(matchAll, c.Args().Slice()...)
if len(paths) == 0 || (len(paths) == 1 && paths[0] == "all") {
return mysys.ScanAllDisks(matchAll)
}

return mysys.ScanDisks(matchAll, paths...)
}

func diskWipe(c *cli.Context) error {
mysys := linux.System()

disks, err := getDiskSet(mysys, c.Args().Slice()...)

if err != nil {
return err
}

for _, d := range disks {
fmt.Printf("%s\n%s\n", d.String(), d.Details())
if err = mysys.Wipe(d); err != nil {
return err
}
}

return nil
Expand Down
23 changes: 20 additions & 3 deletions linux/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,14 +326,31 @@ func getPartName(s string) [72]byte {
return b
}

func zeroPathStartEnd(fpath string, start int64, last int64) error {
fp, err := os.OpenFile(fpath, os.O_RDWR, 0)
func wipeDisk(disk disko.Disk) error {
fp, err := os.OpenFile(disk.Path, os.O_RDWR, 0)
if err != nil {
return err
}
defer fp.Close()

return zeroStartEnd(fp, start, last)
if err := zeroStartEnd(fp, int64(0), int64(disk.Size)); err != nil {
return err
}

for _, p := range disk.Partitions {
// The point of this operation is to wipe. Avoid out of range errors
// that could happen as part of a bad partition table.
end := disk.Size
if end > p.Last {
end = disk.Size
}

if err := zeroStartEnd(fp, int64(p.Start), int64(end)); err != nil {
return err
}
}

return nil
}

// zeroStartEnd - zero the start and end provided with 1MiB bytes of zeros.
Expand Down
120 changes: 108 additions & 12 deletions linux/disk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package linux

import (
"fmt"
"io"
"io/ioutil"
"os"
"path"
Expand Down Expand Up @@ -117,9 +118,8 @@ func TestGetAttachType(t *testing.T) {
}))
}

func genTempGptDisk(tmpd string) (disko.Disk, error) {
func genTempGptDisk(tmpd string, fsize uint64) (disko.Disk, error) {
fpath := path.Join(tmpd, "mydisk")
fsize := uint64(200 * 1024 * 1024) // nolint:gomnd

disk := disko.Disk{
Name: "mydisk",
Expand All @@ -141,19 +141,22 @@ func genTempGptDisk(tmpd string) (disko.Disk, error) {
return disk, fmt.Errorf("Expected 1 free space, found %d", fs)
}

part := disko.Partition{
Start: fs[0].Start,
Last: fs[0].Last,
Type: partid.LinuxLVM,
Name: "mytest partition",
ID: disko.GenGUID(),
Number: uint(1),
}
parts := disko.PartitionSet{
1: disko.Partition{
Start: fs[0].Start,
Last: fs[0].Last,
Type: partid.LinuxLVM,
Name: "mytest partition",
ID: disko.GenGUID(),
Number: uint(1),
}}

if err := addPartitionSet(disk, disko.PartitionSet{part.Number: part}); err != nil {
if err := addPartitionSet(disk, parts); err != nil {
return disk, err
}

disk.Partitions = parts

return disk, nil
}

Expand Down Expand Up @@ -298,6 +301,99 @@ func TestMyPartitionMBR(t *testing.T) {
}
}

// nolint: funlen
func TestWipeDisk(t *testing.T) {
tmpd, err := ioutil.TempDir("", "disko_test")
if err != nil {
t.Fatalf("Failed to create tempdir: %s", err)
}

mib := uint64(1024 * 1024) // nolint: gomnd

defer os.RemoveAll(tmpd)

disk, err := genTempGptDisk(tmpd, 50*mib) // nolint:gomnd
if err != nil {
t.Fatalf("Creation of temp disk failed: %s", err)
}

if len(disk.Partitions) == 0 {
t.Fatalf("Found no partitions on the disk from genTempGptDisk")
}

fp, err := os.OpenFile(disk.Path, os.O_RDWR, 0)
if err != nil {
t.Fatalf("Failed to open disk %s", disk.Path)
}

buf := make([]byte, 1024)

for i := 0; i < 1024; i++ {
buf[i] = 0xFF
}

// write 2MiB of 0xFF at first partition.
// Wipe should zero the first MiB
if _, err := fp.Seek(int64(disk.Partitions[1].Start), io.SeekStart); err != nil {
t.Errorf("failed seek to part1 start: %s", err)
}

for i := 0; i < (2*int(mib))/len(buf); i++ {
if n, err := fp.Write(buf); n != len(buf) || err != nil {
t.Fatalf("failed to write 255 at %d\n", i)
}
}
fp.Close()

if err := wipeDisk(disk); err != nil {
t.Errorf("Failed wipe of disk: %s", err)
}

fp, err = os.OpenFile(disk.Path, os.O_RDWR, 0)
if err != nil {
t.Errorf("Failed opening %s after wipe: %s", disk.Path, err)
}

for _, c := range [](struct {
start uint64
size int
val byte
label string
}){
{0, int(mib), 0x00, "disk start"},
{disk.Partitions[1].Start, int(mib), 0x00, "part1 start"},
{disk.Partitions[1].Start + mib, int(mib), 0xFF, "scribbled 1"},
{disk.Size - mib, int(mib), 0x00, "disk end"},
} {
if _, err := fp.Seek(int64(c.start), io.SeekStart); err != nil {
t.Errorf("Failed seek for %s: %s", c.label, err)
continue
}

buf := make([]byte, c.size)
readlen, err := io.ReadFull(fp, buf)

if err != nil {
t.Errorf("Failed read of %d from fp for %s: %s", len(buf), c.label, err)
continue
}

if readlen != c.size {
t.Errorf("Read %d expected %d for %s: %s", readlen, c.size, c.label, err)
continue
}

for i := 0; i < c.size; i++ {
if buf[i] != c.val {
t.Errorf("%s: %d found %d expected %d", c.label, i, buf[i], c.val)
break
}
}
}

fp.Close()
}

func TestDeletePartition(t *testing.T) {
tmpd, err := ioutil.TempDir("", "disko_test")
if err != nil {
Expand All @@ -306,7 +402,7 @@ func TestDeletePartition(t *testing.T) {

defer os.RemoveAll(tmpd)

disk, err := genTempGptDisk(tmpd)
disk, err := genTempGptDisk(tmpd, 200*1024*1024) // nolint:gomnd
if err != nil {
t.Fatalf("Creation of temp disk failed: %s", err)
}
Expand Down
2 changes: 1 addition & 1 deletion linux/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func (ls *linuxSystem) DeletePartition(d disko.Disk, number uint) error {
}

func (ls *linuxSystem) Wipe(d disko.Disk) error {
if err := zeroPathStartEnd(d.Path, int64(0), int64(d.Size)); err != nil {
if err := wipeDisk(d); err != nil {
return err
}

Expand Down

0 comments on commit 8b51eb3

Please sign in to comment.