From 4f6a8f5d575e264e09ac574b9be0a4c441143521 Mon Sep 17 00:00:00 2001 From: "Ian A.Mason" Date: Sun, 1 Nov 2020 10:49:22 -0800 Subject: [PATCH] Polishing the file type stuff, and adding a test or two, for prosperity. --- shared/filetypes.go | 53 ++++++++++++++++++++++++++++++++++++++++----- tests/entry_test.go | 45 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 5 deletions(-) diff --git a/shared/filetypes.go b/shared/filetypes.go index f868d56..63e582e 100644 --- a/shared/filetypes.go +++ b/shared/filetypes.go @@ -42,7 +42,7 @@ import ( "strings" ) -//BinaryType is the 'intersection' of elf.Type and macho.Type and partitions +// BinaryType is the 'intersection' of elf.Type and macho.Type and partitions // the binary world into categories we are most interested in. Missing is // ARCHIVE but that is because it is not an elf format, so we cannot entirely // eliminate the use of the 'file' utility (cf getFileType below). @@ -59,6 +59,49 @@ const ( BinaryShared BinaryType = 3 ) +func (bt BinaryType) String() string { + switch bt { + case BinaryUnknown: + return "Unknown" + case BinaryObject: + return "Object" + case BinaryExecutable: + return "Executable" + case BinaryShared: + return "Library" + default: + return "Error" + } +} + +// GetBinaryType gets the binary type of the given path +func GetBinaryType(path string) (bt BinaryType) { + bt = BinaryUnknown + plain := IsPlainFile(path) + if !plain { + return + } + // try the format that suits the platform first + operatingSys := runtime.GOOS + switch operatingSys { + case "linux", "freebsd": + bt, _ = ElfFileType(path) + case "darwin": + bt, _ = MachoFileType(path) + } + if bt != BinaryUnknown { + return + } + // try the other format instead + switch operatingSys { + case "linux", "freebsd": + bt, _ = MachoFileType(path) + case "darwin": + bt, _ = ElfFileType(path) + } + return +} + func elfType2BinaryType(et elf.Type) (bt BinaryType) { bt = BinaryUnknown switch et { @@ -95,8 +138,8 @@ func machoType2BinaryType(mt macho.Type) (bt BinaryType) { return } -// isPlainFile returns true if the file is stat-able (i.e. exists etc), and is not a directory, else it returns false. -func isPlainFile(objectFile string) (ok bool) { +// IsPlainFile returns true if the file is stat-able (i.e. exists etc), and is not a directory, else it returns false. +func IsPlainFile(objectFile string) (ok bool) { info, err := os.Stat(objectFile) if os.IsNotExist(err) || info.IsDir() { return @@ -109,7 +152,7 @@ func isPlainFile(objectFile string) (ok bool) { } func injectableViaFileType(objectFile string) (ok bool, err error) { - plain := isPlainFile(objectFile) + plain := IsPlainFile(objectFile) if !plain { return } @@ -151,7 +194,7 @@ func MachoFileType(objectFile string) (code BinaryType, err error) { //IsObjectFileForOS returns true if the given file is an object file for the given OS, using the debug/elf and debug/macho packages. func IsObjectFileForOS(objectFile string, operatingSys string) (ok bool, err error) { - plain := isPlainFile(objectFile) + plain := IsPlainFile(objectFile) if !plain { return } diff --git a/tests/entry_test.go b/tests/entry_test.go index 5eca10a..41cf5e1 100644 --- a/tests/entry_test.go +++ b/tests/entry_test.go @@ -100,3 +100,48 @@ func Test_obscure_functionality(t *testing.T) { fmt.Println("Extraction OK") } } + +func Test_file_type(t *testing.T) { + fictionalFile := "HopefullyThereIsNotAFileCalledThisNearBy.txt" + dataDir := "../data" + sourceFile := "../data/helloworld.c" + objectFile := "../data/bhello.notanextensionthatwerecognize" + exeFile := "../data/bhello" + fmt.Printf("GetBinaryType(%v) = %v\n", fictionalFile, shared.GetBinaryType(fictionalFile)) + fmt.Printf("GetBinaryType(%v) = %v\n", dataDir, shared.GetBinaryType(dataDir)) + fmt.Printf("GetBinaryType(%v) = %v\n", sourceFile, shared.GetBinaryType(sourceFile)) + fmt.Printf("GetBinaryType(%v) = %v\n", objectFile, shared.GetBinaryType(objectFile)) + fmt.Printf("GetBinaryType(%v) = %v\n", exeFile, shared.GetBinaryType(exeFile)) + + plain := shared.IsPlainFile(fictionalFile) + if plain { + t.Errorf("shared.IsPlainFile(%v) returned %v\n", fictionalFile, plain) + } else { + fmt.Printf("shared.IsPlainFile(%v) returned %v\n", fictionalFile, plain) + } + plain = shared.IsPlainFile(dataDir) + if plain { + t.Errorf("shared.IsPlainFile(%v) returned %v\n", dataDir, plain) + } else { + fmt.Printf("shared.IsPlainFile(%v) returned %v\n", dataDir, plain) + } + plain = shared.IsPlainFile(sourceFile) + if !plain { + t.Errorf("shared.IsPlainFile(%v) returned %v\n", sourceFile, plain) + } else { + fmt.Printf("shared.IsPlainFile(%v) returned %v\n", sourceFile, plain) + } + plain = shared.IsPlainFile(objectFile) + if !plain { + t.Errorf("shared.IsPlainFile(%v) returned %v\n", objectFile, plain) + } else { + fmt.Printf("shared.IsPlainFile(%v) returned %v\n", objectFile, plain) + } + plain = shared.IsPlainFile(exeFile) + if !plain { + t.Errorf("shared.IsPlainFile(%v) returned %v\n", exeFile, plain) + } else { + fmt.Printf("shared.IsPlainFile(%v) returned %v\n", exeFile, plain) + } + +}