| | |
| | |
| | |
| |
|
| | package exec |
| |
|
| | import ( |
| | "errors" |
| | "io/fs" |
| | "os" |
| | "path/filepath" |
| | "strings" |
| | ) |
| |
|
| | |
| | var ErrNotFound = errors.New("executable file not found in %PATH%") |
| |
|
| | func chkStat(file string) error { |
| | d, err := os.Stat(file) |
| | if err != nil { |
| | return err |
| | } |
| | if d.IsDir() { |
| | return fs.ErrPermission |
| | } |
| | return nil |
| | } |
| |
|
| | func hasExt(file string) bool { |
| | i := strings.LastIndex(file, ".") |
| | if i < 0 { |
| | return false |
| | } |
| | return strings.LastIndexAny(file, `:\/`) < i |
| | } |
| |
|
| | func findExecutable(file string, exts []string) (string, error) { |
| | if len(exts) == 0 { |
| | return file, chkStat(file) |
| | } |
| | if hasExt(file) { |
| | if chkStat(file) == nil { |
| | return file, nil |
| | } |
| | |
| | |
| | } |
| | for _, e := range exts { |
| | if f := file + e; chkStat(f) == nil { |
| | return f, nil |
| | } |
| | } |
| | if hasExt(file) { |
| | return "", fs.ErrNotExist |
| | } |
| | return "", ErrNotFound |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func LookPath(file string) (string, error) { |
| | if err := validateLookPath(file); err != nil { |
| | return "", &Error{file, err} |
| | } |
| |
|
| | return lookPath(file, pathExt()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func lookExtensions(path, dir string) (string, error) { |
| | if err := validateLookPath(path); err != nil { |
| | return "", &Error{path, err} |
| | } |
| |
|
| | if filepath.Base(path) == path { |
| | path = "." + string(filepath.Separator) + path |
| | } |
| | exts := pathExt() |
| | if ext := filepath.Ext(path); ext != "" { |
| | for _, e := range exts { |
| | if strings.EqualFold(ext, e) { |
| | |
| | return path, nil |
| | } |
| | } |
| | } |
| | if dir == "" { |
| | return lookPath(path, exts) |
| | } |
| | if filepath.VolumeName(path) != "" { |
| | return lookPath(path, exts) |
| | } |
| | if len(path) > 1 && os.IsPathSeparator(path[0]) { |
| | return lookPath(path, exts) |
| | } |
| | dirandpath := filepath.Join(dir, path) |
| | |
| | lp, err := lookPath(dirandpath, exts) |
| | if err != nil { |
| | return "", err |
| | } |
| | ext := strings.TrimPrefix(lp, dirandpath) |
| | return path + ext, nil |
| | } |
| |
|
| | func pathExt() []string { |
| | var exts []string |
| | x := os.Getenv(`PATHEXT`) |
| | if x != "" { |
| | for e := range strings.SplitSeq(strings.ToLower(x), `;`) { |
| | if e == "" { |
| | continue |
| | } |
| | if e[0] != '.' { |
| | e = "." + e |
| | } |
| | exts = append(exts, e) |
| | } |
| | } else { |
| | exts = []string{".com", ".exe", ".bat", ".cmd"} |
| | } |
| | return exts |
| | } |
| |
|
| | |
| | func lookPath(file string, exts []string) (string, error) { |
| | if strings.ContainsAny(file, `:\/`) { |
| | f, err := findExecutable(file, exts) |
| | if err == nil { |
| | return f, nil |
| | } |
| | return "", &Error{file, err} |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | var ( |
| | dotf string |
| | dotErr error |
| | ) |
| | if _, found := os.LookupEnv("NoDefaultCurrentDirectoryInExePath"); !found { |
| | if f, err := findExecutable(filepath.Join(".", file), exts); err == nil { |
| | if execerrdot.Value() == "0" { |
| | execerrdot.IncNonDefault() |
| | return f, nil |
| | } |
| | dotf, dotErr = f, &Error{file, ErrDot} |
| | } |
| | } |
| |
|
| | path := os.Getenv("path") |
| | for _, dir := range filepath.SplitList(path) { |
| | if dir == "" { |
| | |
| | |
| | continue |
| | } |
| |
|
| | if f, err := findExecutable(filepath.Join(dir, file), exts); err == nil { |
| | if dotErr != nil { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | dotfi, dotfiErr := os.Lstat(dotf) |
| | fi, fiErr := os.Lstat(f) |
| | if dotfiErr != nil || fiErr != nil || !os.SameFile(dotfi, fi) { |
| | return dotf, dotErr |
| | } |
| | } |
| |
|
| | if !filepath.IsAbs(f) { |
| | if execerrdot.Value() != "0" { |
| | |
| | |
| | |
| | |
| | if dotErr == nil { |
| | dotf, dotErr = f, &Error{file, ErrDot} |
| | } |
| | continue |
| | } |
| | execerrdot.IncNonDefault() |
| | } |
| | return f, nil |
| | } |
| | } |
| |
|
| | if dotErr != nil { |
| | return dotf, dotErr |
| | } |
| | return "", &Error{file, ErrNotFound} |
| | } |
| |
|