aboutsummaryrefslogtreecommitdiff
path: root/utils/filesystem.go
diff options
context:
space:
mode:
Diffstat (limited to 'utils/filesystem.go')
-rw-r--r--utils/filesystem.go124
1 files changed, 124 insertions, 0 deletions
diff --git a/utils/filesystem.go b/utils/filesystem.go
new file mode 100644
index 0000000..bb8c53e
--- /dev/null
+++ b/utils/filesystem.go
@@ -0,0 +1,124 @@
+// Package utils contains various utility functions to support the
+// main tools-golang packages.
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+package utils
+
+import (
+ "crypto/md5"
+ "crypto/sha1"
+ "crypto/sha256"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+// GetAllFilePaths takes a path to a directory (including an optional slice of
+// path patterns to ignore), and returns a slice of relative paths to all files
+// in that directory and its subdirectories (excluding those that are ignored).
+func GetAllFilePaths(dirRoot string, pathsIgnored []string) ([]string, error) {
+ // paths is a _pointer_ to a slice -- not just a slice.
+ // this is so that it can be appropriately modified by append
+ // in the sub-function.
+ paths := &[]string{}
+ prefix := strings.TrimSuffix(dirRoot, "/")
+
+ err := filepath.Walk(dirRoot, func(path string, fi os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ // don't include path if it's a directory
+ if fi.IsDir() {
+ return nil
+ }
+ // don't include path if it's a symbolic link
+ if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
+ return nil
+ }
+
+ shortPath := strings.TrimPrefix(path, prefix)
+
+ // don't include path if it should be ignored
+ if pathsIgnored != nil && ShouldIgnore(shortPath, pathsIgnored) {
+ return nil
+ }
+
+ // if we got here, record the path
+ *paths = append(*paths, shortPath)
+ return nil
+ })
+
+ return *paths, err
+}
+
+// GetHashesForFilePath takes a path to a file on disk, and returns
+// SHA1, SHA256 and MD5 hashes for that file as strings.
+func GetHashesForFilePath(p string) (string, string, string, error) {
+ f, err := os.Open(p)
+ if err != nil {
+ return "", "", "", err
+ }
+ defer f.Close()
+
+ var ssha1, ssha256, smd5 string
+ hSHA1 := sha1.New()
+ hSHA256 := sha256.New()
+ hMD5 := md5.New()
+ hMulti := io.MultiWriter(hSHA1, hSHA256, hMD5)
+
+ if _, err := io.Copy(hMulti, f); err != nil {
+ f.Close()
+ return "", "", "", err
+ }
+ ssha1 = fmt.Sprintf("%x", hSHA1.Sum(nil))
+ ssha256 = fmt.Sprintf("%x", hSHA256.Sum(nil))
+ smd5 = fmt.Sprintf("%x", hMD5.Sum(nil))
+
+ return ssha1, ssha256, smd5, nil
+}
+
+// ShouldIgnore compares a file path to a slice of file path patterns,
+// and determines whether that file should be ignored because it matches
+// any of those patterns.
+func ShouldIgnore(fileName string, pathsIgnored []string) bool {
+ fDirs, fFile := filepath.Split(fileName)
+
+ for _, pattern := range pathsIgnored {
+ // split into dir(s) and filename
+ patternDirs, patternFile := filepath.Split(pattern)
+ patternDirStars := strings.HasPrefix(patternDirs, "**")
+ if patternDirStars {
+ patternDirs = patternDirs[2:]
+ }
+
+ // case 1: specific file
+ if !patternDirStars && patternDirs == fDirs && patternFile != "" && patternFile == fFile {
+ return true
+ }
+
+ // case 2: all files in specific directory
+ if !patternDirStars && strings.HasPrefix(fDirs, patternDirs) && patternFile == "" {
+ return true
+ }
+
+ // case 3: specific file in any dir
+ if patternDirStars && patternDirs == "/" && patternFile != "" && patternFile == fFile {
+ return true
+ }
+
+ // case 4: specific file in any matching subdir
+ if patternDirStars && strings.Contains(fDirs, patternDirs) && patternFile != "" && patternFile == fFile {
+ return true
+ }
+
+ // case 5: any file in any matching subdir
+ if patternDirStars && strings.Contains(fDirs, patternDirs) && patternFile == "" {
+ return true
+ }
+
+ }
+
+ // if no match, don't ignore
+ return false
+}