Skip to content

Commit

Permalink
Merge pull request #267 from projectdiscovery/standard-dirs
Browse files Browse the repository at this point in the history
add cache dir
  • Loading branch information
Mzack9999 authored Oct 10, 2023
2 parents bbca45a + 60268dc commit b741916
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 38 deletions.
52 changes: 14 additions & 38 deletions folder/folderutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,23 @@ package folderutil
import (
"errors"
"os"
"os/user"
"path/filepath"
"runtime"
"strings"

fileutil "github.com/projectdiscovery/utils/file"
mapsutil "github.com/projectdiscovery/utils/maps"
)

var (
// Separator evaluated at runtime
Separator = string(os.PathSeparator)
// Remove source directory after successful sync
RemoveSourceDirAfterSync = true
// writeablePathCache is a cache of writeable paths
writeablePathCache = mapsutil.SyncLockMap[string, struct{}]{
Map: make(map[string]struct{}),
}
)

const (
Expand Down Expand Up @@ -145,55 +151,25 @@ func agnosticSplit(path string) (parts []string) {
return
}

// HomeDirOrDefault tries to obtain the user's home directory and
// returns the default if it cannot be obtained.
func HomeDirOrDefault(defaultDirectory string) string {
if user, err := user.Current(); err == nil && IsWritable(user.HomeDir) {
return user.HomeDir
}
if homeDir, err := os.UserHomeDir(); err == nil && IsWritable(homeDir) {
return homeDir
}
return defaultDirectory
}

// IsWritable checks if a path is writable by attempting to create a temporary file.
// Note: It's recommended to minimize the use of this function because it involves file creation.
// If performance is a concern, consider declaring a global variable in the module using this and initialize it once.
// It caches writable paths to avoid unnecessary file operations.
func IsWritable(path string) bool {
if _, ok := writeablePathCache.Get(path); ok {
return true
}
if !fileutil.FolderExists(path) {
return false
}

tmpfile, err := os.CreateTemp(path, "test")
if err != nil {
return false
}
defer os.Remove(tmpfile.Name())
_ = tmpfile.Close()
_ = os.Remove(tmpfile.Name())
_ = writeablePathCache.Set(path, struct{}{})
return true
}

// UserConfigDirOrDefault returns the user config directory or defaultConfigDir in case of error
func UserConfigDirOrDefault(defaultConfigDir string) string {
userConfigDir, err := os.UserConfigDir()
if err != nil {
return defaultConfigDir
}
return userConfigDir
}

// AppConfigDirOrDefault returns the app config directory
func AppConfigDirOrDefault(defaultAppConfigDir string, toolName string) string {
userConfigDir := UserConfigDirOrDefault("")
if userConfigDir == "" {
return filepath.Join(defaultAppConfigDir, toolName)
}
return filepath.Join(userConfigDir, toolName)
}

// Remove source directory after successful sync
var RemoveSourceDirAfterSync = true

// SyncDirectory sync all files and non-empty directories from source to destination folder
// optionally removes source directory and removes source
func SyncDirectory(source, destination string) error {
Expand Down
59 changes: 59 additions & 0 deletions folder/std_dirs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package folderutil

import (
"fmt"
"os"
"os/user"
"path/filepath"
)

// Below Contains utils for standard directories
// which should be used by tools to store data
// and configuration files respectively

// HomeDirOrDefault tries to obtain the user's home directory and
// returns the default if it cannot be obtained.
func HomeDirOrDefault(defaultDirectory string) string {
if homeDir, err := os.UserHomeDir(); err == nil && IsWritable(homeDir) {
return homeDir
}
if user, err := user.Current(); err == nil && IsWritable(user.HomeDir) {
return user.HomeDir
}
return defaultDirectory
}

// UserConfigDirOrDefault returns the user config directory or defaultConfigDir in case of error
func UserConfigDirOrDefault(defaultConfigDir string) string {
userConfigDir, err := os.UserConfigDir()
if err != nil {
return defaultConfigDir
}
return userConfigDir
}

// AppConfigDirOrDefault returns the app config directory
func AppConfigDirOrDefault(defaultAppConfigDir string, toolName string) string {
userConfigDir := UserConfigDirOrDefault("")
if userConfigDir == "" {
return filepath.Join(defaultAppConfigDir, toolName)
}
return filepath.Join(userConfigDir, toolName)
}

// AppCacheDirOrDefault returns the user cache directory or defaultCacheDir in case of error
func AppCacheDirOrDefault(defaultCacheDir string, toolName string) string {
userCacheDir, err := os.UserCacheDir()
if err != nil || userCacheDir == "" {
return filepath.Join(defaultCacheDir, toolName)
}
return filepath.Join(userCacheDir, toolName)
}

// Prints the standard directories for a tool
func PrintStdDirs(toolName string) {
appConfigDir := AppConfigDirOrDefault("", toolName)
appCacheDir := AppCacheDirOrDefault("", toolName)
fmt.Printf("[+] %v %-13v: %v\n", toolName, "AppConfigDir", appConfigDir)
fmt.Printf("[+] %v %-13v: %v\n", toolName, "AppCacheDir", appCacheDir)
}

0 comments on commit b741916

Please sign in to comment.