commit 959a7c3cfb75424bb4230848732a6c4657c8949a Author: mitch Date: Fri Dec 31 01:32:24 2021 -0500 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..085f9fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,105 @@ +# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig + +# Created by https://www.gitignore.io/api/macos,visualstudiocode,terraform,windows +# Edit at https://www.gitignore.io/?templates=macos,visualstudiocode,terraform,windows + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Terraform ### +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* +*.plan + +# Crash log files +crash.log + +# Ignore any .tfvars files that are generated automatically for each Terraform run. Most +# .tfvars files are managed as part of configuration and so should be included in +# version control. +# +# example.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json +secrets.tfvars + +# Include override files you do wish to add to version control using negated pattern +# +# !example_override.tf + +### VisualStudioCode ### +.vscode/* +#!.vscode/settings.json +#!.vscode/tasks.json +#!.vscode/launch.json +#!.vscode/extensions.json + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.gitignore.io/api/macos,visualstudiocode,terraform,windows + +# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) +.vscode/* + +.idea \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..d06f51b --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,5 @@ +"THE BEER-WARE LICENSE" (Revision 42) + + wrote this file. As long as you retain this notice you +can do whatever you want with this stuff. If we meet some day, and you think +this stuff is worth it, you can buy me a beer in return \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..340a8bf --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +#################################################### +# Build Application +#################################################### +build: + go build -o diskutil +#################################################### +# Perform nothing +#################################################### +all: + @echo "Nothing to do." +#################################################### +# help feature +#################################################### +help: + @echo '' + @echo 'Usage: make [TARGET]' + @echo 'Targets:' + @echo ' build go build -o diskutil' + @echo ' all nothing to do' + @echo '' \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d6b0098 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +##DiskUtil +A simple program for various commonly used disk utilities + +## Requirements +- go compiler + +## Install +`mv diskutil /usr/local/bin/` + +## Commands +### wipe [-bs int] [-dod enable/disable] target + -bs defaults to 1024 + -dod: defaults to disabled + This feature will saturate a volume with random data 5 times before + overriding with 0's. Default behavior will just write 0's to the volume +### clone [-bs int] source target + -bs defaults to 1024 +## sample usage + `diskutil wipe /dev/sda` + `diskutil wipe -dod=enabled /dev/sda` + `diskutil clone my_cool_iso.iso /dev/sdb` + `diskutil clone -bs=4096 my_cool_iso.iso /dev/sdb` \ No newline at end of file diff --git a/clone.go b/clone.go new file mode 100644 index 0000000..d729b20 --- /dev/null +++ b/clone.go @@ -0,0 +1,45 @@ +package main + +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return + * ---------------------------------------------------------------------------- + */ + +import ( + "io" + "os" +) + +/** +clone copies the contents of cloneSource to cloneTarget +@param cloneBs int is the block size used for the cloning +@param cloneSource string is the source file / volume for the clone +@param cloneTarget string is the target file / volume for the clone +*/ +func clone(cloneBs int, cloneSource string, cloneTarget string) { + p := make([]byte, cloneBs) + fSource, err := os.Open(cloneSource) + defer fSource.Close() + errorHandler(err) + //todo add file not found handling + fTarget, err := os.OpenFile(cloneTarget, os.O_WRONLY, 0644) + defer fTarget.Close() + errorHandler(err) + //todo progress indicator + for { + n, err := fSource.Read(p) + if err == io.EOF { + _, err = fTarget.Write(p[:n]) + errorHandler(err) + break + } + errorHandler(err) + _, err = fTarget.Write(p[:n]) + errorHandler(err) + } + fTarget.Sync() +} diff --git a/diskutil b/diskutil new file mode 100755 index 0000000..d50d710 Binary files /dev/null and b/diskutil differ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..80a43a8 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module diskutil + +go 1.17 diff --git a/main.go b/main.go new file mode 100644 index 0000000..7e8f9ec --- /dev/null +++ b/main.go @@ -0,0 +1,59 @@ +package main + +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return + * ---------------------------------------------------------------------------- + */ + +import ( + "flag" + "fmt" + "os" +) + +func errorHandler(e error) { + if e != nil { + panic(e) + } +} + +func main() { + wipeCmd := flag.NewFlagSet("wipe", flag.ExitOnError) + wipeDod := wipeCmd.Bool("dod", false, "enable") + wipeBs := wipeCmd.Int("bs", 1024, "block size") + + cloneCmd := flag.NewFlagSet("clone", flag.ExitOnError) + cloneBs := cloneCmd.Int("bs", 1024, "block size") + + if len(os.Args) < 2 { + fmt.Println("Expected 'wipe' or 'clone' subcommands") + os.Exit(1) + } + + switch os.Args[1] { + case "wipe": + wipeCmd.Parse(os.Args[2:]) + if len(wipeCmd.Args()) > 1 { + fmt.Println("Only one volume to wipe is supported") + os.Exit(1) + } + wipeDisk := wipeCmd.Args()[0] + wipe(*wipeDod, *wipeBs, wipeDisk) + case "clone": + cloneCmd.Parse(os.Args[2:]) + if len(cloneCmd.Args()) > 2 { + fmt.Println("Only one input and one output volume is supported") + os.Exit(1) + } + cloneSource := cloneCmd.Args()[0] + cloneTarget := cloneCmd.Args()[1] + clone(*cloneBs, cloneSource, cloneTarget) + default: + fmt.Println("Expected 'wipe' or 'clone' subcommands") + os.Exit(1) + } +} diff --git a/wipe.go b/wipe.go new file mode 100644 index 0000000..df045db --- /dev/null +++ b/wipe.go @@ -0,0 +1,112 @@ +package main + +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return + * ---------------------------------------------------------------------------- + */ + +import ( + "crypto/rand" + "fmt" + "io" + "os" + "time" +) + +/** +wipe calls writeToDisk with correct arguments for dod wipe or wipe with zeros +@param wipeDod bool -- boolean for enable/disable random data over-write +@param blocksize int -- block size for each write iteration +@param wipeDisk string -- volume to wipe +*/ +func wipe(wipeDod bool, blocksize int, wipeDisk string) { + if wipeDod { + for i := 0; i < 5; i++ { + fmt.Println("Starting wipe number", i+1, "at", time.Now()) + writeToDisk(wipeDisk, blocksize, "random") + fmt.Println("Writing ones to disk at", time.Now()) + writeToDisk(wipeDisk, blocksize, "one") + } + } + fmt.Println("Writing zeros to disk at", time.Now()) + writeToDisk(wipeDisk, blocksize, "zero") +} + +/** +writeToDisk opens a reader / writer file handler then iterates through the reader blocks and writes them as it does +@param wipeDisk string is the string of the volume/file to wipe +@param blocksize int is the int of the block size +@param writetype string expects "one", or "zero" other values will return randomByte() +*/ +func writeToDisk(wipeDisk string, blocksize int, writeType string) { + zero := buildZero(blocksize) + p := make([]byte, blocksize) + fTarget, err := os.OpenFile(wipeDisk, os.O_WRONLY, 0644) + defer fTarget.Close() + errorHandler(err) + fRead, err := os.Open(wipeDisk) + defer fRead.Close() + i := 0 + for { + var block []byte + i++ + n, err := fRead.Read(p) + if err == io.EOF { + _, err := fTarget.Write(zero[:n]) + errorHandler(err) + break + } + errorHandler(err) + if writeType == "zero" { + block = buildZero(blocksize) + } else if writeType == "one" { + block = buildOne(blocksize) + } else { + block = randomByte(blocksize) + } + _, err = fTarget.Write(block[:n]) + } + fTarget.Sync() +} + +/** +randomByte creates a []byte with random data +@param blocksize int -- size of the block to build +returns []byte containing random data +*/ +func randomByte(blocksize int) []byte { + block := make([]byte, blocksize) + _, err := rand.Read(block) + errorHandler(err) + return block +} + +/** +buildZero creates []byte of 0 +@param blocksize int -- size of the block to build +returns []byte of size blocksize containing {0..0} +*/ +func buildZero(blocksize int) []byte { + block := make([]byte, blocksize) + for i := 0; i < blocksize; i++ { + block[i] = 0 + } + return block +} + +/** +buildOne creates []byte of 1's +@param blocksize int -- size of block to build +returns []byte of size blocksize containing {0xff..0xff} +*/ +func buildOne(blocksize int) []byte { + block := make([]byte, blocksize) + for i := 0; i < blocksize; i++ { + block[i] = 0xff + } + return block +}