fix(windows): do not follow app store symlinks

This commit is contained in:
Jan De Dobbeleer 2024-10-23 12:58:55 +02:00 committed by Jan De Dobbeleer
parent d64de61436
commit ab39417dc2
4 changed files with 2 additions and 109 deletions

View file

@ -10,6 +10,7 @@ import (
httplib "net/http" httplib "net/http"
"net/http/httputil" "net/http/httputil"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv" "strconv"
@ -388,7 +389,7 @@ func (term *Terminal) CommandPath(command string) string {
return path return path
} }
path, err := term.LookPath(command) path, err := exec.LookPath(command)
if err == nil { if err == nil {
term.cmdCache.Set(command, path) term.cmdCache.Set(command, path)
term.Debug(path) term.Debug(path)

View file

@ -4,7 +4,6 @@ package runtime
import ( import (
"os" "os"
"os/exec"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -148,10 +147,6 @@ func (term *Terminal) ConvertToLinuxPath(path string) string {
return path return path
} }
func (term *Terminal) LookPath(command string) (string, error) {
return exec.LookPath(command)
}
func (term *Terminal) DirIsWritable(path string) bool { func (term *Terminal) DirIsWritable(path string) bool {
defer term.Trace(time.Now(), path) defer term.Trace(time.Now(), path)
return unix.Access(path, unix.W_OK) == nil return unix.Access(path, unix.W_OK) == nil

View file

@ -4,8 +4,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"os" "os"
"os/exec"
"path/filepath"
"strings" "strings"
"syscall" "syscall"
"time" "time"
@ -251,17 +249,3 @@ func (term *Terminal) Connection(connectionType ConnectionType) (*Connection, er
term.Error(fmt.Errorf("Network type '%s' not found", connectionType)) term.Error(fmt.Errorf("Network type '%s' not found", connectionType))
return nil, &NotImplemented{} return nil, &NotImplemented{}
} }
func (term *Terminal) LookPath(command string) (string, error) {
winAppPath := filepath.Join(term.Getenv("LOCALAPPDATA"), `\Microsoft\WindowsApps\`, command)
if !strings.HasSuffix(winAppPath, ".exe") {
winAppPath += ".exe"
}
path, err := exec.LookPath(command)
if err == nil && path != winAppPath {
return path, nil
}
return readWinAppLink(winAppPath)
}

View file

@ -6,7 +6,6 @@ import (
"reflect" "reflect"
"strings" "strings"
"syscall" "syscall"
"unicode/utf16"
"unsafe" "unsafe"
"github.com/jandedobbeleer/oh-my-posh/src/regex" "github.com/jandedobbeleer/oh-my-posh/src/regex"
@ -116,46 +115,6 @@ func queryWindowTitles(processName, windowTitleRegex string) (string, error) {
return title, nil return title, nil
} }
type REPARSE_DATA_BUFFER struct { //nolint: revive
ReparseTag uint32
ReparseDataLength uint16
Reserved uint16
DUMMYUNIONNAME byte
}
type GenericDataBuffer struct {
DataBuffer [1]uint8
}
type AppExecLinkReparseBuffer struct {
Version uint32
StringList [1]uint16
}
func (rb *AppExecLinkReparseBuffer) Path() (string, error) {
UTF16ToStringPosition := func(s []uint16) (string, int) {
for i, v := range s {
if v == 0 {
s = s[0:i]
return string(utf16.Decode(s)), i
}
}
return "", 0
}
stringList := (*[0xffff]uint16)(unsafe.Pointer(&rb.StringList[0]))[0:]
var link string
var position int
for i := 0; i <= 2; i++ {
link, position = UTF16ToStringPosition(stringList)
position++
if position >= len(stringList) {
return "", errors.New("invalid AppExecLinkReparseBuffer")
}
stringList = stringList[position:]
}
return link, nil
}
var ( var (
advapi = syscall.NewLazyDLL("advapi32.dll") advapi = syscall.NewLazyDLL("advapi32.dll")
procGetAce = advapi.NewProc("GetAce") procGetAce = advapi.NewProc("GetAce")
@ -350,49 +309,3 @@ func (env *Terminal) Memory() (*Memory, error) {
PhysicalPercentUsed: float64(memStat.MemoryLoad), PhysicalPercentUsed: float64(memStat.MemoryLoad),
}, nil }, nil
} }
// openSymlink calls CreateFile Windows API with FILE_FLAG_OPEN_REPARSE_POINT
// parameter, so that Windows does not follow symlink, if path is a symlink.
// openSymlink returns opened file handle.
func openSymlink(path string) (syscall.Handle, error) {
p, err := syscall.UTF16PtrFromString(path)
if err != nil {
return 0, err
}
attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
// Use FILE_FLAG_OPEN_REPARSE_POINT, otherwise CreateFile will follow symlink.
// See https://docs.microsoft.com/en-us/windows/desktop/FileIO/symbolic-link-effects-on-file-systems-functions#createfile-and-createfiletransacted
attrs |= syscall.FILE_FLAG_OPEN_REPARSE_POINT
h, err := syscall.CreateFile(p, 0, 0, nil, syscall.OPEN_EXISTING, attrs, 0)
if err != nil {
return 0, err
}
return h, nil
}
func readWinAppLink(path string) (string, error) {
h, err := openSymlink(path)
if err != nil {
return "", err
}
defer syscall.CloseHandle(h) //nolint: errcheck
rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
var bytesReturned uint32
err = syscall.DeviceIoControl(h, syscall.FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
if err != nil {
return "", err
}
rdb := (*REPARSE_DATA_BUFFER)(unsafe.Pointer(&rdbbuf[0]))
rb := (*GenericDataBuffer)(unsafe.Pointer(&rdb.DUMMYUNIONNAME))
appExecLink := (*AppExecLinkReparseBuffer)(unsafe.Pointer(&rb.DataBuffer))
if appExecLink.Version != 3 {
return "", errors.New("unknown AppExecLink version")
}
return appExecLink.Path()
}