Skip to content

Commit

Permalink
Merge pull request #90 from smoser/feature/disk-wipe-partitions
Browse files Browse the repository at this point in the history
Make Wipe() wipe partitions, Add demo disk wipe.
  • Loading branch information
Scott Moser authored Sep 10, 2020
2 parents a6d85b9 + 8b51eb3 commit 3712019
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 3712019

Please sign in to comment.