Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 2.1k
Introduce canonicalization library for Windows subst drives#22129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
4f3004275ee4af009ed60e06ce00c95a8ab9976a7a726705bFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,8 @@ | ||
| | code/Program.cs:0:0:0:0 | code/Program.cs | | | ||
| | code/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs:0:0:0:0 | code/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs | | | ||
| | code/obj/Debug/net9.0/dotnet_build.AssemblyInfo.cs:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.AssemblyInfo.cs | | | ||
| | code/obj/Debug/net9.0/dotnet_build.GlobalUsings.g.cs:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.GlobalUsings.g.cs | | | ||
| | code/obj/Debug/net9.0/dotnet_build.dll:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.dll | | | ||
| | code/Program.cs:0:0:0:0 | code/Program.cs | relative | | ||
| | code/dotnet_build.csproj:0:0:0:0 | code/dotnet_build.csproj | relative | | ||
| | code/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs:0:0:0:0 | code/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs | relative | | ||
| | code/obj/Debug/net9.0/dotnet_build.AssemblyInfo.cs:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.AssemblyInfo.cs | relative | | ||
| | code/obj/Debug/net9.0/dotnet_build.GlobalUsings.g.cs:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.GlobalUsings.g.cs | relative | | ||
| | code/obj/Debug/net9.0/dotnet_build.dll:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.dll | relative | | ||
| | code/obj/dotnet_build.csproj.nuget.g.props:0:0:0:0 | code/obj/dotnet_build.csproj.nuget.g.props | relative | | ||
| | file://:0:0:0:0 | | | | ||
| | file://Z:/dotnet_build.csproj:0:0:0:0 | Z:/dotnet_build.csproj | relative | | ||
| | file://Z:/obj/dotnet_build.csproj.nuget.g.props:0:0:0:0 | Z:/obj/dotnet_build.csproj.nuget.g.props | relative | |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| //go:build !windows | ||
| package util | ||
| // ResolvePath is a no-op on non-Windows platforms. | ||
| func ResolvePath(path string) string { return path } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| //go:build windows | ||
| package util | ||
| import ( | ||
| "os" | ||
| "path/filepath" | ||
| "syscall" | ||
| "unsafe" | ||
| "golang.org/x/sys/windows" | ||
| ) | ||
| var ( | ||
| dll *syscall.DLL | ||
| procResolve *syscall.Proc | ||
| procFree *syscall.Proc | ||
| available bool | ||
| ) | ||
| func init() { | ||
| dist := os.Getenv("CODEQL_DIST") | ||
| if dist == "" { | ||
| return | ||
| } | ||
| dllPath := filepath.Join(dist, "tools", "win64", "canonicalize.dll") | ||
| d, err := syscall.LoadDLL(dllPath) | ||
| if err != nil { | ||
| return | ||
| } | ||
| p, err := d.FindProc("resolve_subst") | ||
| if err != nil { | ||
| d.Release() | ||
| return | ||
| } | ||
| f, err := d.FindProc("resolve_subst_free") | ||
| if err != nil { | ||
| d.Release() | ||
| return | ||
| } | ||
| dll = d | ||
| procResolve = p | ||
| procFree = f | ||
| available = true | ||
| } | ||
| // If "path" is an absolute path starting with a "subst"ed drive letter, return an | ||
| // equivalent path with the drive letter replaced by its target. Otherwise return | ||
| // "path" unchanged. | ||
| func ResolvePath(path string) string { | ||
| if len(path) < 3 { | ||
| return path | ||
| } | ||
| if path[1] != ':' { | ||
| return path | ||
| } | ||
| if path[2] != '\\' && path[2] != '/' { | ||
| return path | ||
| } | ||
| c := path[0] | ||
| if !((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { | ||
| return path | ||
| } | ||
| resolved, ok := resolveDrive(path[:3]) | ||
| if !ok { | ||
| return path | ||
| } | ||
| return resolved + path[2:] | ||
| } | ||
| // Given a drive root like "X:\" (or "X:/"), returns the path that drive is | ||
| // "subst"ed to. Returns false if the drive is not "subst"ed or an error occurred. | ||
| func resolveDrive(driveRoot string) (string, bool) { | ||
| if !available { | ||
| return "", false | ||
| } | ||
| driveBytes, err := windows.ByteSliceFromString(driveRoot) | ||
| if err != nil { | ||
| return "", false | ||
| } | ||
| ret, _, _ := procResolve.Call(uintptr(unsafe.Pointer(&driveBytes[0]))) | ||
| if ret == 0 { | ||
| return "", false | ||
| } | ||
| result := windows.BytePtrToString((*byte)(unsafe.Pointer(ret))) | ||
| if procFree != nil { | ||
| procFree.Call(ret) | ||
| } | ||
| return result, true | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| | file://Z:/main.go:0:0:0:0 | Z:/main.go | relative | | ||
| | code/main.go:0:0:0:0 | code/main.go | relative | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| package com.semmle.util.files; | ||
| import com.semmle.util.exception.Exceptions; | ||
| import java.io.File; | ||
| import java.net.URISyntaxException; | ||
| import java.nio.file.Path; | ||
| import java.nio.file.Paths; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| /** | ||
| * Resolves Windows {@code subst}ed drive letters to their underlying paths. On non-Windows | ||
| * platforms, or when the native library failed to load, resolving will be a no-op. | ||
| */ | ||
| public class SubstResolver { | ||
| private static final boolean available; | ||
| static { | ||
| boolean loaded = false; | ||
| // Cheap check to see that we are on Windows. Avoids static initialization of {@code Env}. | ||
| if (File.separatorChar == '\\') { | ||
| String dist = System.getenv("CODEQL_DIST"); | ||
| if (dist != null && !dist.isEmpty()) { | ||
| try { | ||
| Path library = Paths.get(dist).resolve("tools") | ||
| .resolve("win64").resolve("canonicalize.dll").toAbsolutePath(); | ||
| System.load(library.toString()); | ||
| loaded = true; | ||
| } catch (RuntimeException | UnsatisfiedLinkError ignored) { | ||
| Exceptions.ignore(ignored, "Fall back to resolution being a no-op."); | ||
| } | ||
| } | ||
| } | ||
| available = loaded; | ||
| } | ||
| private SubstResolver() {} | ||
| /** | ||
| * Given a drive root like {@code "X:\\"} (or {@code "X:/"}), returns the path that drive is | ||
| * {@code subst}ed to, or {@code null} if the drive root was not subst drive or if an internal | ||
| * error occurred. | ||
| */ | ||
| private static native String nativeResolveSubst(String driveRoot); | ||
| /** | ||
| * If {@code f} is an absolute path starting with a {@code subst}ed drive letter, return an | ||
| * equivalent path with the drive letter replaced by its target. Otherwise return {@code f} | ||
| * unchanged. | ||
| */ | ||
| public static File resolve(File f) { | ||
| if (!available) { | ||
| return f; | ||
| } | ||
| String path = f.getPath(); | ||
| if (path.length() < 3 || path.charAt(1) != ':') { | ||
| return f; | ||
| } | ||
| char sep = path.charAt(2); | ||
| if (sep != '\\' && sep != '/') { | ||
| return f; | ||
| } | ||
| if (!isDriveLetter(path.charAt(0))) { | ||
| return f; | ||
| } | ||
| String resolved; | ||
| try { | ||
| resolved = nativeResolveSubst(path.substring(0, 3)); | ||
| } catch (RuntimeException | UnsatisfiedLinkError ignored) { | ||
| Exceptions.ignore(ignored, "Fall back to resolution being a no-op."); | ||
| return f; | ||
| } | ||
| if (resolved == null) { | ||
| return f; | ||
| } | ||
| // Append the remainder of the original path. The native side strips away | ||
| // any trailing separator. | ||
| return new File(resolved + path.substring(2)); | ||
| } | ||
| private static boolean isDriveLetter(char c) { | ||
| return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| | code/Test.class:0:0:0:0 | Test | relative | | ||
| | code/test1.java:0:0:0:0 | test1 | relative | | ||
| | code/test2.kt:0:0:0:0 | test2 | relative | | ||
| | file://:0:0:0:0 | | | | ||
| | file://:0:0:0:0 | | | | ||
| | file://Z:/Test.class:0:0:0:0 | Test | relative | | ||
| | file://Z:/test1.java:0:0:0:0 | test1 | relative | | ||
| | file://Z:/test2.kt:0:0:0:0 | test2 | relative | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,2 @@ | ||
| | file://Z:/main.js:0:0:0:0 | Z:/main.js | relative | | ||
| | file://Z:/test.ts:0:0:0:0 | Z:/test.ts | relative | | ||
| | code/main.js:0:0:0:0 | code/main.js | relative | | ||
| | code/test.ts:0:0:0:0 | code/test.ts | relative | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| | code/main.py:0:0:0:0 | code/main.py | | | ||
| | code/main.py:0:0:0:0 | code/main.py | relative | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,2 @@ | ||
| | code/test.rb:0:0:0:0 | code/test.rb | | | ||
| | code/test.rb:0:0:0:0 | code/test.rb | relative | | ||
| | file://:0:0:0:0 | | | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,2 @@ | ||
| | code/test.rs:0:0:0:0 | code/test.rs | | | ||
| | code/test.rs:0:0:0:0 | code/test.rs | relative | | ||
| | file://:0:0:0:0 | | | |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.