commit 0aec8da266ce302e1dda22dd291fea0d5e1ffa88 Author: Glauber Ferreira Date: Tue Dec 10 19:21:07 2024 -0300 primeiro commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1f94d9a --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +.PHONY: build run clean + +build: + go build -o bin/file-checksum-monitor ./cmd/file-checksum-monitor + +run: build + ./bin/file-checksum-monitor + +clean: + rm -rf bin/ diff --git a/cmd/file-checksum-monitor/main.go b/cmd/file-checksum-monitor/main.go new file mode 100644 index 0000000..4b2e3df --- /dev/null +++ b/cmd/file-checksum-monitor/main.go @@ -0,0 +1,67 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/alpharde/file-checksum-monitor/internal/library" +) + +func main() { + dbPath := "libraries.db" + manager, err := library.NewLibraryManager(dbPath) + if err != nil { + fmt.Printf("Error initializing LibraryManager: %v\n", err) + return + } + + addCmd := flag.NewFlagSet("add", flag.ExitOnError) + scanCmd := flag.NewFlagSet("scan", flag.ExitOnError) + compareCmd := flag.NewFlagSet("compare", flag.ExitOnError) + + addName := addCmd.String("name", "", "Name of the library") + addDir := addCmd.String("directory", "", "Path to the library directory") + + scanName := scanCmd.String("name", "", "Name of the library to scan") + + compareName := compareCmd.String("name", "", "Name of the library to compare") + + if len(os.Args) < 2 { + fmt.Println("Expected 'add', 'scan', or 'compare' subcommands") + os.Exit(1) + } + + switch os.Args[1] { + case "add": + addCmd.Parse(os.Args[2:]) + if *addName == "" || *addDir == "" { + fmt.Println("Usage: add -name -directory ") + os.Exit(1) + } + if err := manager.AddLibrary(*addName, *addDir); err != nil { + fmt.Printf("Error adding library: %v\n", err) + } + case "scan": + scanCmd.Parse(os.Args[2:]) + if *scanName == "" { + fmt.Println("Usage: scan -name ") + os.Exit(1) + } + if err := manager.ScanLibrary(*scanName); err != nil { + fmt.Printf("Error scanning library: %v\n", err) + } + case "compare": + compareCmd.Parse(os.Args[2:]) + if *compareName == "" { + fmt.Println("Usage: compare -name ") + os.Exit(1) + } + if err := manager.CompareLibrary(*compareName); err != nil { + fmt.Printf("Error comparing library: %v\n", err) + } + default: + fmt.Println("Unknown subcommand") + os.Exit(1) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d9c104b --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module file-checksum-monitor + +go 1.23.2 diff --git a/internal/library/checksum.go b/internal/library/checksum.go new file mode 100644 index 0000000..51accd9 --- /dev/null +++ b/internal/library/checksum.go @@ -0,0 +1,24 @@ +package library + +import ( + "crypto/sha256" + "encoding/hex" + "io/ioutil" + "os" +) + +func calculateChecksum(filePath string) (string, error) { + file, err := os.Open(filePath) + if err != nil { + return "", err + } + defer file.Close() + + data, err := ioutil.ReadAll(file) + if err != nil { + return "", err + } + + hash := sha256.Sum256(data) + return hex.EncodeToString(hash[:]), nil +} diff --git a/internal/library/database.go b/internal/library/database.go new file mode 100644 index 0000000..eb80c91 --- /dev/null +++ b/internal/library/database.go @@ -0,0 +1,23 @@ +package library + +import ( + "database/sql" +) + +func initializeDatabase(db *sql.DB) error { + _, err := db.Exec(` + CREATE TABLE IF NOT EXISTS libraries ( + name TEXT PRIMARY KEY, + directory TEXT + ); + + CREATE TABLE IF NOT EXISTS files ( + library_name TEXT, + file_path TEXT, + checksum TEXT, + failed BOOLEAN DEFAULT FALSE, + PRIMARY KEY (library_name, file_path) + ); + `) + return err +} diff --git a/internal/library/manager.go b/internal/library/manager.go new file mode 100644 index 0000000..09296a2 --- /dev/null +++ b/internal/library/manager.go @@ -0,0 +1,127 @@ +package library + +import ( + "database/sql" + "fmt" + "os" + "path/filepath" + "sync" + "sync/atomic" +) + +type LibraryManager struct { + Libraries map[string]string + Mutex sync.Mutex + db *sql.DB +} + +func NewLibraryManager(dbPath string) (*LibraryManager, error) { + db, err := sql.Open("sqlite3", dbPath) + if err != nil { + return nil, err + } + + if err := initializeDatabase(db); err != nil { + return nil, err + } + + return &LibraryManager{ + Libraries: make(map[string]string), + db: db, + }, nil +} + +func (lm *LibraryManager) AddLibrary(name, directory string) error { + lm.Mutex.Lock() + defer lm.Mutex.Unlock() + + if _, exists := lm.Libraries[name]; exists { + return fmt.Errorf("Library %s already exists", name) + } + + lm.Libraries[name] = directory + + _, err := lm.db.Exec("INSERT OR IGNORE INTO libraries (name, directory) VALUES (?, ?)", name, directory) + if err != nil { + return err + } + + fmt.Printf("Library %s added.\n", name) + return nil +} + +func (lm *LibraryManager) ScanLibrary(name string) error { + dir, exists := lm.Libraries[name] + if !exists { + return fmt.Errorf("Library %s does not exist", name) + } + + var fileCount int64 + + err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.Mode().IsRegular() { + return nil + } + + checksum, err := calculateChecksum(path) + if err != nil { + return err + } + + _, err = lm.db.Exec("INSERT OR REPLACE INTO files (library_name, file_path, checksum, failed) VALUES (?, ?, ?, FALSE)", name, path, checksum) + if err != nil { + return err + } + + atomic.AddInt64(&fileCount, 1) + return nil + }) + + if err != nil { + return err + } + + fmt.Printf("Scanned %d files in library %s\n", fileCount, name) + return nil +} + +func (lm *LibraryManager) CompareLibrary(name string) error { + rows, err := lm.db.Query("SELECT file_path, checksum FROM files WHERE library_name = ?", name) + if err != nil { + return err + } + defer rows.Close() + + var mismatches int + + for rows.Next() { + var filePath, storedChecksum string + if err := rows.Scan(&filePath, &storedChecksum); err != nil { + return err + } + + currentChecksum, err := calculateChecksum(filePath) + if err != nil { + // Mark the file as failed if it cannot be read + _, updateErr := lm.db.Exec("UPDATE files SET failed = TRUE WHERE library_name = ? AND file_path = ?", name, filePath) + if updateErr != nil { + return fmt.Errorf("error marking file as failed: %v", updateErr) + } + continue + } + + if currentChecksum != storedChecksum { + mismatches++ + _, err := lm.db.Exec("UPDATE files SET failed = TRUE WHERE library_name = ? AND file_path = ?", name, filePath) + if err != nil { + return err + } + } + } + + fmt.Printf("Comparison completed. %d mismatches found in library %s\n", mismatches, name) + return nil +}