Skip to content

Commit

Permalink
Major refactor.
Browse files Browse the repository at this point in the history
Removed unnecessary libs, improved readability and code flow.
  • Loading branch information
Azmekk committed Feb 28, 2024
1 parent 2f40254 commit 349d0a9
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 83 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ go.work

#Others
/bin
/src/bin
6 changes: 3 additions & 3 deletions src/build_script.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ $env:GOARCH = "amd64"
echo "Setting the target operating system to windows"
$env:GOOS = "windows"
echo "Building for windows x86-64"
go build -o ../bin/recoverdiscordcache_windows.exe
go build -o ./bin/recoverdiscordcache_windows.exe

echo "Setting the target operating system to linux"
$env:GOOS = "linux"
echo "Building for linux x86-64"
go build -o ../bin/recoverdiscordcache_linux
go build -o ./bin/recoverdiscordcache_linux

echo "Setting the target operating system to darwin (macOS)"
$env:GOOS = "darwin"
echo "Building for mac x86-64"
go build -o ../bin/recoverdiscordcache_mac
go build -o ./bin/recoverdiscordcache_mac

echo "Resetting the environment variables"
Remove-Item Env:\GOARCH
Expand Down
4 changes: 1 addition & 3 deletions src/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,5 @@ module azmekk/recoverdiscordcache
go 1.20

require (
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/h2non/filetype v1.1.3 // indirect
golang.org/x/net v0.8.0 // indirect
github.com/h2non/filetype v1.1.3
)
4 changes: 0 additions & 4 deletions src/go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
14 changes: 8 additions & 6 deletions src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,28 @@ package main

import (
"fmt"
"io/ioutil"
"os"
)

var knownUnreadableFiles = []string{"index", "data_0", "data_1", "data_2", "data_3"}

func main() {
fmt.Println("Locating discord cache folder")
discordCacheFolder := getDiscordCacheFolderBasedOnOS()

fmt.Println("Reading cache folder for all saved files.")
cachedFiles, err := ioutil.ReadDir(discordCacheFolder)
dirEntries, err := os.ReadDir(discordCacheFolder)
if err != nil {
fmt.Println("Error reading folder:", err)
os.Exit(1)
}

fmt.Println("Recovering found files.")
for _, file := range cachedFiles {
readAndSeparateFile(file, discordCacheFolder)
for _, dirEntry := range dirEntries {
fileInfo, err := dirEntry.Info()
if err != nil {
fmt.Println("Error reading file ", dirEntry.Name())
continue
}
readAndSeparateFile(fileInfo, discordCacheFolder)
}

fmt.Println("Done!")
Expand Down
139 changes: 72 additions & 67 deletions src/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@ package main

import (
"bytes"
"errors"
"fmt"
"io/fs"
"io/ioutil"
"mime"
"os"
"path/filepath"
"runtime"

"github.com/gabriel-vasile/mimetype"
"github.com/h2non/filetype"
)

type cachedFileData struct {
fileExtension string
startingByte int
}

var knownUnreadableFiles = [...]string{"index", "data_0", "data_1", "data_2", "data_3"}
var exeDir string = getExeDir()

func readAndSeparateFile(fileInfo fs.FileInfo, discordCacheFolder string) {
if fileInfo.IsDir() {
return
Expand All @@ -26,49 +32,51 @@ func readAndSeparateFile(fileInfo fs.FileInfo, discordCacheFolder string) {
}

filePath := filepath.Join(discordCacheFolder, fileInfo.Name())
exeDir := getExeDir()
buffer := getFileBuffer(filePath, fileInfo)
fileType, unknownFileTypeErr, firstFileByte := getFileMimeType(buffer)
buffer = buffer[firstFileByte:]
if unknownFileTypeErr != nil {

buffer, err := getFileBuffer(filePath, fileInfo)
if err != nil {
fmt.Println("Could not read buffer for file: ", fileInfo.Name())
return
} else if fileType == "application/octet-stream" {
}

fileData, err := getNewFileData(buffer)

if err != nil && err.Error() == "unknown filetype" {
return
}
fileExtensions := getFileExtensions(fileType, filePath)

if len(fileExtensions) == 0 {
if err != nil {
fmt.Println("Encountered error while trying to determine file type for file: ", fileInfo.Name())
return
}
fileExtension := fileExtensions[0]

saveDir := getSaveDirAndCreateIfNotExists(exeDir, fileExtension)
sameFileAlreadyExists, newFilePath := getNewFilePath(buffer, saveDir, fileInfo.Name(), fileExtension, 0)
saveDir := getOrCreateSaveDir(exeDir, fileData.fileExtension)

if sameFileAlreadyExists {
buffer = buffer[fileData.startingByte:]
fileExists, newFilePath := getNewFilePath(buffer, saveDir, fileInfo.Name(), fileData.fileExtension)

if fileExists {
return
}

err := ioutil.WriteFile(newFilePath, buffer, 0644)
err = os.WriteFile(newFilePath, buffer, 0644)
if err != nil {
fmt.Println(fmt.Sprintf("Error writing file %s:%s", filePath, err))

fmt.Println("Error writing file: ", filePath, " due to err: ", err)
return
}
}

func doesFileNameExist(filePath string) bool {
func fileNameExists(filePath string) bool {
_, err := os.Stat(filePath)
if os.IsNotExist(err) {
return false
}
return true
return !os.IsNotExist(err)
}

func isSameFile(buffer []byte, existingFilePath string) bool {
fileData, err := ioutil.ReadFile(existingFilePath)
fileData, err := os.ReadFile(existingFilePath)
if err != nil {
fmt.Println(fmt.Sprintf("Error reading file to compare with buffer %s: %s", existingFilePath, err))
os.Exit(1)
fmt.Println("Error reading file: ", existingFilePath, "to compare with buffer due to err: ", err)
return true
}

if bytes.Equal(fileData, buffer) {
Expand All @@ -78,67 +86,53 @@ func isSameFile(buffer []byte, existingFilePath string) bool {
}
}

func getNewFilePath(buffer []byte, saveDir string, fileName string, fileExtension string, depth int) (bool, string) {
depth++
filePath := filepath.Join(saveDir, fileName+fileExtension)
func getNewFilePath(buffer []byte, saveDir string, fileName string, fileExtension string) (bool, string) {
filePath := filepath.Join(saveDir, fmt.Sprintf("%s.%s", fileName, fileExtension))

fileNameAlreadyExists := doesFileNameExist(filePath)

if fileNameAlreadyExists && isSameFile(buffer, filePath) {
if fileNameExists(filePath) && isSameFile(buffer, filePath) {
return true, ""
} else if fileNameAlreadyExists {
fileName = fmt.Sprintf("%s_%d", fileName, depth)
return getNewFilePath(buffer, saveDir, fileName, fileExtension, depth)
}

return false, filePath
}
i := 0
for fileNameExists(filePath) {
i++
filePath = fmt.Sprintf("%d_%s", i, filePath)
}

func detectOS() string {
os := runtime.GOOS
return os
return false, filePath
}

func getFileBuffer(filePath string, fileInfo fs.FileInfo) []byte {
func getFileBuffer(filePath string, fileInfo fs.FileInfo) ([]byte, error) {
file, err := os.Open(filePath)

if err != nil {
fmt.Println(fmt.Sprintf("Error opening file %s: %s", filePath, err))
os.Exit(1)
fmt.Println("Error opening file: ", filePath, " due to err: ", err)
return nil, errors.New("")
}
defer file.Close()

buffer := make([]byte, fileInfo.Size())
_, err = file.Read(buffer)
if err != nil {
fmt.Println(fmt.Sprintf("Error reading file %s: %s", filePath, err))
os.Exit(1)
fmt.Println("Error reading file: ", filePath, " due to err: ", err)
return nil, errors.New("")
}

return buffer
return buffer, nil
}

func getExeDir() string {
exePath, err := os.Executable()
if err != nil {
fmt.Println("Error retrieving executable path:", err)
fmt.Println("Error retrieving executable path: ", err)
os.Exit(1)
}

return filepath.Dir(exePath)
}

func getFileExtensions(fileType string, filePath string) []string {
fileExtensions, err := mime.ExtensionsByType(fileType)
if err != nil {
fmt.Println(fmt.Sprintf("Error getting extension for mime type %s for file %s: %s", fileType, filePath, err))
os.Exit(1)
}

return fileExtensions
}

func getSaveDirAndCreateIfNotExists(exeDir string, fileExtension string) string {
saveDir := filepath.Join(exeDir, fileExtension[1:])
func getOrCreateSaveDir(exeDir string, fileExtension string) string {
saveDir := filepath.Join(exeDir, fileExtension)
_, err := os.Stat(saveDir)
if os.IsNotExist(err) {
os.Mkdir(saveDir, 0755)
Expand Down Expand Up @@ -182,26 +176,37 @@ func getDiscordCacheFolderBasedOnOS() string {
}
}

func getFileMimeType(buffer []byte) (string, error, int) {
func getNewFileData(buffer []byte) (cachedFileData, error) {
if runtime.GOOS == "windows" {
return mimetype.Detect(buffer).String(), nil, 0
return getFileExtension(buffer)
} else {
return detectUnixFileMIMEType(buffer)
return getFileExtensionLinux(buffer)
}
}

func getFileExtension(buffer []byte) (cachedFileData, error) {
fileInfo, _ := filetype.Match(buffer)
if fileInfo == filetype.Unknown {
return cachedFileData{}, errors.New("unknown filetype")
}

return cachedFileData{fileInfo.Extension, 0}, nil
}

func detectUnixFileMIMEType(buffer []byte) (string, error, int) {
for i := 0; i < 400; i++ {
func getFileExtensionLinux(buffer []byte) (cachedFileData, error) {
for i := 0; i < 70; i++ {
if i >= len(buffer) {
break
}

kind, _ := filetype.Match(buffer[i:])
fileInfo, _ := filetype.Match(buffer[i:])

if kind != filetype.Unknown {
return kind.MIME.Value, nil, i
if fileInfo == filetype.Unknown {
continue
}

return cachedFileData{fileInfo.Extension, 0}, nil
}

return "", fmt.Errorf("Unknown filetype"), 0
return cachedFileData{}, errors.New("unknown filetype")
}

0 comments on commit 349d0a9

Please sign in to comment.