From 20d107a28a2ed27a97e88bc40728f640b0e582f7 Mon Sep 17 00:00:00 2001 From: Meo597 <197331664+Meo597@users.noreply.github.com> Date: Sun, 25 Oct 2026 23:52:22 +0800 Subject: [PATCH] Platform: Consolidate regular file resolution Reuse ResolveRegularFile for Lua loading/signing, local config, and assets. Only evaluate file symlinks when needed, tolerating junction-related resolution failures on a best-effort basis. --- common/platform/filesystem/file.go | 10 +----- common/platform/platform.go | 50 +++++++++++++++++----------- main/commands/all/lua/sign.go | 21 +++++------- main/confloader/external/external.go | 7 ++-- 4 files changed, 41 insertions(+), 47 deletions(-) diff --git a/common/platform/filesystem/file.go b/common/platform/filesystem/file.go index 24cf112e2..f4f27e218 100644 --- a/common/platform/filesystem/file.go +++ b/common/platform/filesystem/file.go @@ -61,15 +61,7 @@ func getAssetFileLocation(file string) (string, os.FileInfo, error) { if err != nil { return "", nil, err } - path := platform.GetAssetLocation(local) - info, err := os.Stat(path) - if err != nil { - return "", nil, err - } - if !info.Mode().IsRegular() { - return "", nil, errors.New("asset is not a regular file") - } - return path, info, nil + return platform.ResolveRegularFile(platform.GetAssetLocation(local)) } func ReadCert(file string) ([]byte, error) { diff --git a/common/platform/platform.go b/common/platform/platform.go index 9a650876a..271c77660 100644 --- a/common/platform/platform.go +++ b/common/platform/platform.go @@ -96,9 +96,6 @@ func GetConfDirPath() string { // ResolveLuaFile finds a local .lua script and returns its resolved absolute path. // Relative paths: XRAY_LOCATION_CONFDIR > XRAY_LOCATION_CONFIG > working dir > executable dir. func ResolveLuaFile(path string) (string, error) { - if path == "" { - return "", errors.New("Lua file path is empty") - } paths := []string{path} if !filepath.IsAbs(path) { paths = nil @@ -117,14 +114,6 @@ func ResolveLuaFile(path string) (string, error) { if err != nil { return "", err } - return resolveLuaTarget(path) -} - -func resolveLuaTarget(path string) (string, error) { - path, err := filepath.EvalSymlinks(path) - if err != nil { - return "", fmt.Errorf("failed to resolve Lua file symlinks: %w", err) - } if filepath.Ext(path) != ".lua" { return "", errors.New("Lua file extension must be .lua") } @@ -134,22 +123,43 @@ func resolveLuaTarget(path string) (string, error) { func resolveFile(paths []string) (string, error) { var tried []string for _, path := range paths { - path, err := filepath.Abs(path) - if err != nil { - return "", fmt.Errorf("failed to resolve file path: %w", err) - } tried = append(tried, path) - info, err := os.Stat(path) + path, _, err := ResolveRegularFile(path) if errors.Is(err, os.ErrNotExist) { continue } if err != nil { - return "", fmt.Errorf("failed to inspect file %q: %w", path, err) - } - if !info.Mode().IsRegular() { - return "", fmt.Errorf("file is not a regular file: %s", path) + return "", err } return path, nil } return "", fmt.Errorf("file not found; tried %q: %w", tried, os.ErrNotExist) } + +// ResolveRegularFile returns an absolute path and metadata of a regular file. +// File symlinks are resolved when possible; otherwise the original path is kept. +func ResolveRegularFile(path string) (string, os.FileInfo, error) { + path, err := filepath.Abs(path) + if err != nil { + return "", nil, fmt.Errorf("failed to resolve file path: %w", err) + } + info, err := os.Lstat(path) + if err != nil { + return "", nil, fmt.Errorf("failed to inspect file %q: %w", path, err) + } + if info.Mode()&os.ModeSymlink != 0 { + // Best effort: EvalSymlinks may fail when junctions are involved. + if resolved, err := filepath.EvalSymlinks(path); err == nil { + path = resolved + } + info, err = os.Stat(path) + if err != nil { + return "", nil, fmt.Errorf("failed to inspect file %q: %w", path, err) + } + } + if !info.Mode().IsRegular() { + return "", nil, fmt.Errorf("file is not a regular file: %s", path) + } + // Hard links are not handled. + return path, info, nil +} diff --git a/main/commands/all/lua/sign.go b/main/commands/all/lua/sign.go index a300e1540..b492d46dc 100644 --- a/main/commands/all/lua/sign.go +++ b/main/commands/all/lua/sign.go @@ -5,6 +5,7 @@ import ( "path/filepath" xlua "github.com/xtls/xray-core/common/lua" + "github.com/xtls/xray-core/common/platform" "github.com/xtls/xray-core/main/commands/base" ) @@ -32,15 +33,15 @@ func executeSign(cmd *base.Command, args []string) { cmd.Usage() } - info, err := os.Stat(args[0]) + input, info, err := platform.ResolveRegularFile(args[0]) if err != nil { base.Fatalf("failed to inspect Lua file: %s", err) } - if !info.Mode().IsRegular() { - base.Fatalf("Lua input is not a regular file: %s", args[0]) + if filepath.Ext(input) != ".lua" { + base.Fatalf("Lua file extension must be .lua") } - code, err := os.ReadFile(args[0]) + code, err := os.ReadFile(input) if err != nil { base.Fatalf("failed to read Lua file: %s", err) } @@ -58,7 +59,7 @@ func executeSign(cmd *base.Command, args []string) { } output := *signOutput if output == "" { - output = args[0] + output = input } if err := writeSignedFile(output, signed, info.Mode().Perm()); err != nil { base.Fatalf("failed to write signed Lua file: %s", err) @@ -66,15 +67,9 @@ func executeSign(cmd *base.Command, args []string) { } func writeSignedFile(path string, code []byte, mode os.FileMode) error { - if info, err := os.Stat(path); err == nil { - if !info.Mode().IsRegular() { - return &os.PathError{Op: "write", Path: path, Err: os.ErrInvalid} - } + if resolved, info, err := platform.ResolveRegularFile(path); err == nil { + path = resolved mode = info.Mode().Perm() - path, err = filepath.EvalSymlinks(path) - if err != nil { - return err - } } else if !os.IsNotExist(err) { return err } diff --git a/main/confloader/external/external.go b/main/confloader/external/external.go index 412890bb2..f01dbadce 100644 --- a/main/confloader/external/external.go +++ b/main/confloader/external/external.go @@ -14,6 +14,7 @@ import ( "github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/errors" + "github.com/xtls/xray-core/common/platform" "github.com/xtls/xray-core/common/utils" "github.com/xtls/xray-core/main/commands/base" "github.com/xtls/xray-core/main/confloader" @@ -58,11 +59,7 @@ func readConfigFile(file *os.File) ([]byte, error) { return nil, err } if info.Mode().IsRegular() { - path, err := filepath.Abs(file.Name()) - if err != nil { - return nil, err - } - path, err = filepath.EvalSymlinks(path) + path, _, err := platform.ResolveRegularFile(file.Name()) if err != nil { return nil, err }