Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
arnavbhatt288 committed Nov 1, 2023
0 parents commit 6896ea9
Show file tree
Hide file tree
Showing 13 changed files with 2,210 additions and 0 deletions.
21 changes: 21 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# Go workspace file
go.work
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
WIP.
13 changes: 13 additions & 0 deletions src/FyneApp.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Details]
Icon = "assets/images/Icon.png"
Name = "Utkirna"
ID = "com.ghativega.Utkirna"
Version = "0.5.0"
Build = 1

[LinuxAndBSD]
GenericName = "Disk Imager"
Categories = ["Disk", "Utility"]
Comment = "A program to write a raw disk image to a removable device or backup a removable device to a raw image file."
Keywords = ["disk imager", "utkirna", "fyne"]
ExecParams = "%F"
Binary file added src/assets/images/Icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
318 changes: 318 additions & 0 deletions src/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,318 @@
package main

import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"os"
"time"
)

type TaskType int

const (
START_WRITE TaskType = iota
START_READ
START_VERIFY
)

func GetTrueImagePath(path string) string {
return path[7:]
}

func determineOptimalSize(numSectors int64, sector int64) int64 {
if numSectors-sector >= int64(1024) {
return int64(1024)
} else {
return numSectors - sector
}
}

func fmtDuration(d time.Duration) string {
d = d.Round(time.Second)
h := d / time.Hour
d -= h * time.Hour
m := d / time.Minute
d -= m * time.Minute
s := d / time.Second
return fmt.Sprintf("%02d:%02d:%02d", h, m, s)
}

func StartTimer(start time.Time, widgets GUI) chan bool {
ch := make(chan bool)
go func() {
for range time.Tick(time.Second) {
select {
case <-ch:
return
default:
elapsed := time.Since(start)
elapsedStr := fmtDuration(elapsed)
widgets.elapsedLabel.SetText(elapsedStr)
}
}
}()
return ch
}

func cleanUp(data *MainData, gui GUI, handles Handles) {
data.bQuitTimer <- true
CloseRequiredHandles(handles)
disableCancelButton(gui, *data)
}

func StartMainTask(data *MainData, gui GUI) {
var err error
var handles Handles

err = GetRequiredHandles(
&handles,
data.selectedDrive,
data.imagePath,
)
if err != nil {
HandleError(
gui,
data,
errors.Join(errors.New("StartMainTask(): GetRequiredHandle failed"), err),
)
return
}

if data.taskType == START_WRITE || data.taskType == START_VERIFY {
WriteVerifyDisk(data, gui, handles)
} else if data.taskType == START_READ {
ReadDisk(data, gui, handles)
}
}

func ReadDisk(data *MainData, gui GUI, handles Handles) {
elapsedTimer := time.Now()
data.bQuitTimer = StartTimer(elapsedTimer, gui)

diskNumSectors, diskSector, err := GetNumDiskSector(handles.hDisk)
if err != nil {
cleanUp(data, gui, handles)
HandleError(gui, data, errors.Join(errors.New("ReadDisk(): GatherSizeInBytes failed"), err))
return
}

if gui.mbrCheck.Checked {
sectorData, err := ReadSectorDataFromHandle(handles.hDisk, 0, 1, 512)
if err != nil {
cleanUp(data, gui, handles)
HandleError(
gui,
data,
errors.Join(errors.New("ReadDisk(): ReadSectorDataFromHandle failed"), err),
)
return
}
diskNumSectors = int64(1)
for i := 0; i < 4; i++ {
partitionStartSector := binary.LittleEndian.Uint32(sectorData[0x1BE+8+16*i:])
partitionNumSectors := binary.LittleEndian.Uint32(sectorData[0x1BE+12+16*i:])

if int64(partitionStartSector+partitionNumSectors) > diskNumSectors {
diskNumSectors = int64(partitionStartSector + partitionNumSectors)
}
}
}

gui.rwProgressBar.Max = float64(diskNumSectors - 1024)
lasti := int64(0)
updateTimer := time.Now()

data.bQuitTask = make(chan bool)
go func() {
for i := int64(0); i < diskNumSectors; i += 1024 {
select {
case <-data.bQuitTask:
return
default:
{
set := determineOptimalSize(diskNumSectors, i)

sectorData, err := ReadSectorDataFromHandle(
handles.hDisk,
i,
set,
diskSector,
)
if err != nil {
cleanUp(data, gui, handles)
HandleError(
gui,
data,
errors.Join(
errors.New("ReadDisk(): ReadSectorDataFromHandle failed"),
err,
),
)
return
}

err = WriteSectorDataFromHandle(handles.hImage, sectorData, i, diskSector)
if err != nil {
cleanUp(data, gui, handles)
HandleError(
gui,
data,
errors.Join(
errors.New("ReadDisk(): WriteSectorDataFromHandle failed"),
err,
),
)
return
}

gui.rwProgressBar.SetValue(float64(i))
if time.Since(updateTimer).Milliseconds() >= 1000 {
mbPerSec := float64(
(int64(diskSector) * (i - lasti)),
) * (1000 / float64(time.Since(updateTimer).Milliseconds())) / 1024.0 / 1024.0
setText := fmt.Sprintf("%f MB/s", mbPerSec)
gui.speedLabel.SetText(setText)
lasti = i
updateTimer = time.Now()
}
}
}
}
cleanUp(data, gui, handles)
}()
}

func WriteVerifyDisk(data *MainData, gui GUI, handles Handles) {
elapsedTimer := time.Now()
data.bQuitTimer = StartTimer(elapsedTimer, gui)

diskNumSectors, diskSector, err := GetNumDiskSector(handles.hDisk)
if err != nil {
cleanUp(data, gui, handles)
HandleError(
gui,
data,
errors.Join(errors.New("WriteVerifyDisk(): GatherSizeInBytes failed"), err),
)
return
}

imageStat, err := os.Stat(data.imagePath)
if err != nil {
cleanUp(data, gui, handles)
HandleError(gui, data, err)
}
imageNumSectors := (imageStat.Size() / int64(diskSector)) + (imageStat.Size() % int64(diskSector))

if imageNumSectors > diskNumSectors {
if gui.ignoreSize.Checked {
imageNumSectors = diskNumSectors
} else {
cleanUp(data, gui, handles)
HandleError(gui, data, errors.New("WriteVerifyDisk(): Size of image is larger than of device"))
return
}
}

gui.rwProgressBar.Max = float64(imageNumSectors - 1024)
lasti := int64(0)
updateTimer := time.Now()

data.bQuitTask = make(chan bool)
go func() {
for i := int64(0); i < imageNumSectors; i += 1024 {
select {
case <-data.bQuitTask:
return
default:
{
numSectors := determineOptimalSize(imageNumSectors, i)

sectorData, err := ReadSectorDataFromHandle(
handles.hImage,
i,
numSectors,
diskSector,
)
if err != nil {
cleanUp(data, gui, handles)
HandleError(
gui,
data,
errors.Join(
errors.New("WriteVerifyDisk(): ReadSectorDataFromHandle failed"),
err,
),
)
return
}

if data.taskType == START_WRITE {
err = WriteSectorDataFromHandle(
handles.hDisk,
sectorData,
i,
diskSector,
)
if err != nil {
cleanUp(data, gui, handles)
HandleError(
gui,
data,
errors.Join(
errors.New(
"WriteVerifyDisk(): WriteSectorDataFromHandle failed",
),
err,
),
)
return
}
}
sectorData2, err := ReadSectorDataFromHandle(
handles.hDisk,
i,
numSectors,
diskSector,
)
if err != nil {
cleanUp(data, gui, handles)
HandleError(
gui,
data,
errors.Join(
errors.New("WriteVerifyDisk(): ReadSectorDataFromHandle failed"),
err,
),
)
return
}

if !bytes.Equal(sectorData, sectorData2) {
cleanUp(data, gui, handles)
strError := fmt.Sprintf(
"WriteVerifyDisk(): Verification failed at sector: %d\n",
i,
)
HandleError(gui, data, errors.New(strError))
return
}

gui.rwProgressBar.SetValue(float64(i))
if time.Since(updateTimer).Milliseconds() >= 1000 {
mbPerSec := float64(
(int64(diskSector) * (i - lasti)),
) * (1000 / float64(time.Since(updateTimer).Milliseconds())) / 1024.0 / 1024.0
setText := fmt.Sprintf("%f MB/s", mbPerSec)
gui.speedLabel.SetText(setText)
lasti = i
updateTimer = time.Now()
}
}
}
}
cleanUp(data, gui, handles)
}()
}
38 changes: 38 additions & 0 deletions src/fsctl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//go:build windows
// +build windows

package main

import "golang.org/x/sys/windows"

const (
FSCTL_LOCK_VOLUME = uint32(0x90018)
FSCTL_UNLOCK_VOLUME = uint32(0x90019)
FSCTL_DISMOUNT_VOLUME = uint32(0x90020)
)

func LockVolume(handle windows.Handle) error {
var bytesReturned uint32
err := windows.DeviceIoControl(handle, FSCTL_LOCK_VOLUME, nil, 0, nil, 0, &bytesReturned, nil)
return err
}

func UnlockVolume(handle windows.Handle) {
var bytesReturned uint32
windows.DeviceIoControl(handle, FSCTL_UNLOCK_VOLUME, nil, 0, nil, 0, &bytesReturned, nil)
}

func UnmountVolume(handle windows.Handle) error {
var bytesReturned uint32
err := windows.DeviceIoControl(
handle,
FSCTL_DISMOUNT_VOLUME,
nil,
0,
nil,
0,
&bytesReturned,
nil,
)
return err
}
Loading

0 comments on commit 6896ea9

Please sign in to comment.