From bb0e08dd883b00e79f173ae3f45406077863930e Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Sun, 5 Oct 2025 21:25:24 +0200 Subject: [PATCH 1/5] clear objects folder before reversing --- main.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/main.go b/main.go index 3a33547..7613e10 100644 --- a/main.go +++ b/main.go @@ -98,6 +98,17 @@ func main() { log.Fatalf("prepForReverse (%s) failed : %v", *modfile, err) } + // clear the objects directory to avoid orphaned files (by removing and recreating) + objectsPath := filepath.Join(*moddir, objectsSubdir) + + if err := os.RemoveAll(objectsPath); err != nil { + log.Fatalf("Error clearing directory %s: %v", objectsPath, err) + } + + if err := os.MkdirAll(objectsPath, 0755); err != nil { + log.Fatalf("Error recreating directory %s: %v", objectsPath, err) + } + r := mod.Reverser{ ModSettingsWriter: ms, LuaWriter: lua, From 9d588bb86e8a24a92526a5f4a875d35604f7f59e Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Mon, 6 Oct 2025 12:51:57 +0200 Subject: [PATCH 2/5] limit deletion to regular mode only --- main.go | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/main.go b/main.go index 7613e10..c13db9a 100644 --- a/main.go +++ b/main.go @@ -92,23 +92,24 @@ func main() { if *objin != "" { *modfile = *objin objs = file.NewJSONOps(filepath.Dir(*objout)) + } else { + // clear the objects directory to avoid orphaned files (by removing and recreating) + objectsPath := filepath.Join(*moddir, objectsSubdir) + + if err := os.RemoveAll(objectsPath); err != nil { + log.Fatalf("Error clearing directory %s: %v", objectsPath, err) + } + + if err := os.MkdirAll(objectsPath, 0755); err != nil { + log.Fatalf("Error recreating directory %s: %v", objectsPath, err) + } } + raw, err := prepForReverse(*moddir, *modfile) if err != nil { log.Fatalf("prepForReverse (%s) failed : %v", *modfile, err) } - // clear the objects directory to avoid orphaned files (by removing and recreating) - objectsPath := filepath.Join(*moddir, objectsSubdir) - - if err := os.RemoveAll(objectsPath); err != nil { - log.Fatalf("Error clearing directory %s: %v", objectsPath, err) - } - - if err := os.MkdirAll(objectsPath, 0755); err != nil { - log.Fatalf("Error recreating directory %s: %v", objectsPath, err) - } - r := mod.Reverser{ ModSettingsWriter: ms, LuaWriter: lua, From e30c1a2da9569a5704a12599dd972af17519edcc Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Thu, 9 Oct 2025 11:26:04 +0200 Subject: [PATCH 3/5] moved code into DirCreator Interface --- file/dirops.go | 18 ++++++++++++++++++ main.go | 10 ++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/file/dirops.go b/file/dirops.go index 62b0341..f33117c 100644 --- a/file/dirops.go +++ b/file/dirops.go @@ -11,6 +11,7 @@ import ( // DirCreator abstracts folder creation type DirCreator interface { CreateDir(relpath string, suggestion string) (string, error) + Clear() error } // DirExplorer allows files and folders to be enumerated @@ -51,6 +52,23 @@ func (d *DirOps) CreateDir(relpath, suggestion string) (string, error) { return dirname, nil } +// Clear removes all contents from the base directory and recreates it. +func (d *DirOps) Clear() error { + log.Printf("Clearing directory: %s", d.base) + + // Remove the directory and all its contents + if err := os.RemoveAll(d.base); err != nil { + return fmt.Errorf("error clearing directory %s: %w", d.base, err) + } + + // Recreate the empty directory + if err := os.MkdirAll(d.base, 0755); err != nil { + return fmt.Errorf("error recreating directory %s: %w", d.base, err) + } + + return nil +} + // ListFilesAndFolders allows for file exploration. returns relateive file or folder names func (d *DirOps) ListFilesAndFolders(relpath string) ([]string, []string, error) { p := filepath.Join(d.base, relpath) diff --git a/main.go b/main.go index c13db9a..bab6dcd 100644 --- a/main.go +++ b/main.go @@ -94,14 +94,8 @@ func main() { objs = file.NewJSONOps(filepath.Dir(*objout)) } else { // clear the objects directory to avoid orphaned files (by removing and recreating) - objectsPath := filepath.Join(*moddir, objectsSubdir) - - if err := os.RemoveAll(objectsPath); err != nil { - log.Fatalf("Error clearing directory %s: %v", objectsPath, err) - } - - if err := os.MkdirAll(objectsPath, 0755); err != nil { - log.Fatalf("Error recreating directory %s: %v", objectsPath, err) + if err := objdir.Clear(); err != nil { + log.Fatalf("Failed to clear objects directory before writing: %v", err) } } From 9670087ee3b5c9f53045eb40928b6ff573d4bf8c Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Thu, 9 Oct 2025 11:28:41 +0200 Subject: [PATCH 4/5] updated fakefiles --- tests/fakefiles.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/fakefiles.go b/tests/fakefiles.go index 6ebe915..304f23e 100644 --- a/tests/fakefiles.go +++ b/tests/fakefiles.go @@ -116,6 +116,11 @@ func (f *FakeFiles) CreateDir(a, b string) (string, error) { return b, nil } +// Clear satisfies DirCreator +func (f *FakeFiles) Clear() error { + return nil +} + // ListFilesAndFolders satisfies DirExplorer func (f *FakeFiles) ListFilesAndFolders(relpath string) ([]string, []string, error) { // ignore non json files. i don't think they Matter From 50728ef78704124cfd9c8d9d67732711cecb5197 Mon Sep 17 00:00:00 2001 From: Chr1Z93 Date: Tue, 14 Oct 2025 18:44:39 +0200 Subject: [PATCH 5/5] added safety check --- file/dirops.go | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/file/dirops.go b/file/dirops.go index f33117c..455bef2 100644 --- a/file/dirops.go +++ b/file/dirops.go @@ -6,8 +6,18 @@ import ( "os" "path" "path/filepath" + "time" ) +// Set of allowed file extensions for the safety check before clearing the objects folder +var allowedExtensions = map[string]struct{}{ + ".json": {}, + ".gmnotes": {}, + ".luascriptstate": {}, + ".ttslua": {}, + ".xml": {}, +} + // DirCreator abstracts folder creation type DirCreator interface { CreateDir(relpath string, suggestion string) (string, error) @@ -52,9 +62,44 @@ func (d *DirOps) CreateDir(relpath, suggestion string) (string, error) { return dirname, nil } +// preClearCheck walks the directory and ensures all files have an allowed extension. +// It returns an error if a file with a disallowed extension is found. +func (d *DirOps) preClearCheck() error { + walkErr := filepath.Walk(d.base, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // Skip directories + if info.IsDir() { + return nil + } + + ext := filepath.Ext(info.Name()) + if _, isAllowed := allowedExtensions[ext]; !isAllowed { + return fmt.Errorf("unsafe file type found: %s", path) + } + return nil + }) + + // If the directory doesn't exist, Walk returns an error. We treat this as "safe". + if os.IsNotExist(walkErr) { + return nil + } + return walkErr +} + // Clear removes all contents from the base directory and recreates it. func (d *DirOps) Clear() error { - log.Printf("Clearing directory: %s", d.base) + log.Println("Performing safety check...") + startTime := time.Now() + + if err := d.preClearCheck(); err != nil { + return fmt.Errorf("pre-clear safety check failed, operation aborted: %w", err) + } + + duration := time.Since(startTime) + log.Printf("Safety check passed in %v. Proceeding with clear.", duration) // Remove the directory and all its contents if err := os.RemoveAll(d.base); err != nil { @@ -66,6 +111,7 @@ func (d *DirOps) Clear() error { return fmt.Errorf("error recreating directory %s: %w", d.base, err) } + log.Printf("Cleared and recreated directory: %s", d.base) return nil }