I need some advice on this piece of code. I'm developing a application in Go to read the content of a file line by line and compare one specific column formed by a hash with others in the same file. I'm trying to catch different hashes to the same filename and get an alert that a file has been changed.
Here's an example of the text file. Each line is formed by filename, hash and computer name:
c:\program files\internet explorer\iexplore.exe;0f3c97716fed8b554a7ec0464d50719f;computer1
c:\program files (x86)\google\chrome\application\chrome.exe;d387a06cd4bf5fcc1b50c3882f41a44e;computer1
c:\windows\system32
otepad.exe;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;computer1
c:\program files\internet explorer\iexplore.exe;BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB;computer1
c:\program files (x86)\google\chrome\application\chrome.exe;d387a06cd4bf5fcc1b50c3882f41a44e;computer1
c:\windows\system32
otepad.exe;f60a9d3a9461f68de0fccebb0c6cb31a;computer1
When running the code I'm getting the same information twice because I used two for. Obviously I just need one occurrence of each. Results:
go run main.go
Original: c:\program files\internet explorer\iexplore.exe 0f3c97716fed8b554a7ec0464d50719f computer1
Violation: c:\program files\internet explorer\iexplore.exe BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB computer1
------
Original: c:\windows\system32
otepad.exe AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA computer1
Violation: c:\windows\system32
otepad.exe f60a9d3a9461f68de0fccebb0c6cb31a computer1
------
Original: c:\program files\internet explorer\iexplore.exe BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB computer1
Violation: c:\program files\internet explorer\iexplore.exe 0f3c97716fed8b554a7ec0464d50719f computer1
------
Original: c:\windows\system32
otepad.exe f60a9d3a9461f68de0fccebb0c6cb31a computer1
Violation: c:\windows\system32
otepad.exe AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA computer1
------
IGNORE THIS LINE []
IGNORE THIS LINE []
Expected result:
c:\program files\internet explorer\iexplore.exe;0f3c97716fed8b554a7ec0464d50719f;computer1
c:\program files\internet explorer\iexplore.exe;BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB;computer1
c:\windows\system32
otepad.exe;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;computer1
c:\windows\system32
otepad.exe;f60a9d3a9461f68de0fccebb0c6cb31a;computer1
I tried break, continue, variables, etc but I think that I'm having trouble with logic to report only one occurrence.
Here's the code (finally):
package main
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"strings"
)
const (
FILE_DIR = "./logs/"
)
func main() {
p := fmt.Println
// List and open all log files
listOfFiles := listDirFiles(FILE_DIR)
for _, file := range listOfFiles {
f, err := os.Open(FILE_DIR + file)
if err != nil {
p("Error when opening the file " + FILE_DIR + file + " .")
break
}
defer f.Close()
var lines []string
scanner := bufio.NewScanner(f)
for scanner.Scan() {
lines = append(lines, scanner.Text()) // Converting the content of a file into a slice
}
results := testViolation(lines)
fmt.Println("IGNORE THIS LINE", results)
}
}
func testViolation(lines []string) []string {
var splitLine []string
for _, f := range lines {
splitLine = strings.Split(f, ";")
for _, c := range lines {
checkLine := strings.Split(c, ";")
if splitLine[0] == checkLine[0] && splitLine[2] == checkLine[2] && splitLine[1] != checkLine[1] {
fmt.Println("Original: ", splitLine[0], splitLine[1], splitLine[2])
fmt.Println("Violation: ", checkLine[0], checkLine[1], checkLine[2])
fmt.Println("------")
}
}
}
return nil
}
func listDirFiles(dir string) []string {
var filesString []string
files, _ := ioutil.ReadDir(dir)
// Convert []os.FileInfo into []string to return
for _, f := range files {
filesString = append(filesString, f.Name())
}
return filesString
}
I really appreciate your help.
Mario.
Use a map[string]string (e.g. mapName[computerName+fileName] = fileHashvalue, for each line check if the map entry exists for the given computer and file name (concatenated string - computerName + fileName) & if so compare with the existing hash value) you can do this in just one range loop instead of two you are using now. Hope this helps.
on testViolation you has (i deleted google chrome entry to better visibility):
line0 =
c:\program files\internetexplorer\iexplore.exe;
0f3c97716fed8b554a7ec0464d50719f;
computer1
line1:
c:\windows\system32
otepad.exe;
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;
computer1
line2:
c:\program files\internetexplorer\iexplore.exe;
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB;
computer1
line3:
c:\windows\system32
otepad.exe;
f60a9d3a9461f68de0fccebb0c6cb31a;
computer1
On your loop:
for _, f := range lines {
splitLine = strings.Split(f, ";")
for _, c := range lines {
// To f == line0, you match with c == line2
// To f == line1, you match with c == line3
// To f == line2, you match with c == line0
// To f == line3, you match with c == line1
checkLine := strings.Split(c, ";")
if splitLine[0] == checkLine[0] && splitLine[2] == checkLine[2] && splitLine[1] != checkLine[1] {
// ...
}
}
}
So, you need delete line when you find a match. it's not very sexy, but it's work
more simply: I think, you sould build a map["string-untilFirst';'"][]"stringhash+computer" on begin function.
// map[string][]string
So, just you count number element:
for _, v := range myMap {
if len(v) > 1 {
// if you need compare computer you can split here or use:
// map[string]map[string][]string
// "there are a diff on v[0] and v[1] * len(v)"
}
}
I hope help you ;) Good continuation on you project !