pathutil_windows.go raw

   1  package pathutil
   2  
   3  import (
   4  	"errors"
   5  	"io/fs"
   6  	"os"
   7  	"path/filepath"
   8  	"strings"
   9  
  10  	"golang.org/x/sys/windows"
  11  )
  12  
  13  // UserHomeDir returns the home directory of the current user.
  14  func UserHomeDir() string {
  15  	return KnownFolder(windows.FOLDERID_Profile, []string{"USERPROFILE"}, nil)
  16  }
  17  
  18  // Exists returns true if the specified path exists.
  19  func Exists(path string) bool {
  20  	fi, err := os.Lstat(path)
  21  	if fi != nil && fi.Mode()&os.ModeSymlink != 0 {
  22  		_, err = filepath.EvalSymlinks(path)
  23  	}
  24  
  25  	return err == nil || errors.Is(err, fs.ErrExist)
  26  }
  27  
  28  // ExpandHome substitutes `%USERPROFILE%` at the start of the specified `path`.
  29  func ExpandHome(path string) string {
  30  	home := UserHomeDir()
  31  	if path == "" || home == "" {
  32  		return path
  33  	}
  34  	if strings.HasPrefix(path, `%USERPROFILE%`) {
  35  		return filepath.Join(home, path[13:])
  36  	}
  37  
  38  	return path
  39  }
  40  
  41  // KnownFolder returns the location of the folder with the specified ID.
  42  // If that fails, the folder location is determined by reading the provided
  43  // environment variables (the first non-empty read value is returned).
  44  // If that fails as well, the first non-empty fallback is returned.
  45  // If all of the above fails, the function returns an empty string.
  46  func KnownFolder(id *windows.KNOWNFOLDERID, envVars []string, fallbacks []string) string {
  47  	if id != nil {
  48  		flags := []uint32{windows.KF_FLAG_DEFAULT, windows.KF_FLAG_DEFAULT_PATH}
  49  		for _, flag := range flags {
  50  			p, _ := windows.KnownFolderPath(id, flag|windows.KF_FLAG_DONT_VERIFY)
  51  			if p != "" {
  52  				return p
  53  			}
  54  		}
  55  	}
  56  
  57  	for _, envVar := range envVars {
  58  		p := os.Getenv(envVar)
  59  		if p != "" {
  60  			return p
  61  		}
  62  	}
  63  
  64  	for _, fallback := range fallbacks {
  65  		if fallback != "" {
  66  			return fallback
  67  		}
  68  	}
  69  
  70  	return ""
  71  }
  72