From 164281c34bc4d5bec5ffa2ae5c92297b592d6728 Mon Sep 17 00:00:00 2001 From: Varun Gokulnath Date: Thu, 11 Dec 2025 17:46:08 -0800 Subject: [PATCH] Addressed Feedback Signed-off-by: Varun Gokulnath --- reparse.go | 8 +++- reparse_lx_test.go | 97 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 4 deletions(-) diff --git a/reparse.go b/reparse.go index 013fe15..9847fbd 100644 --- a/reparse.go +++ b/reparse.go @@ -16,6 +16,8 @@ const ( reparseTagMountPoint = 0xA0000003 reparseTagSymlink = 0xA000000C reparseTagLxSymlink = 0xA000001D // WSL/MSYS2 native symlinks + + lxSymlinkVersion = 2 // LX symlink format version ) type reparseDataBuffer struct { @@ -102,6 +104,9 @@ func isDriveLetter(c byte) bool { // EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink, // mount point, or LX symlink. func EncodeReparsePoint(rp *ReparsePoint) []byte { + if rp == nil { + return nil + } if rp.IsLxSymlink { return encodeLxReparsePoint(rp) } @@ -110,7 +115,6 @@ func EncodeReparsePoint(rp *ReparsePoint) []byte { func encodeLxReparsePoint(rp *ReparsePoint) []byte { // LX symlink: 4-byte version + UTF-8 target - version := uint32(2) targetBytes := []byte(rp.Target) dataLength := 4 + len(targetBytes) @@ -118,7 +122,7 @@ func encodeLxReparsePoint(rp *ReparsePoint) []byte { _ = binary.Write(&b, binary.LittleEndian, uint32(reparseTagLxSymlink)) _ = binary.Write(&b, binary.LittleEndian, uint16(dataLength)) _ = binary.Write(&b, binary.LittleEndian, uint16(0)) - _ = binary.Write(&b, binary.LittleEndian, version) + _ = binary.Write(&b, binary.LittleEndian, uint32(lxSymlinkVersion)) _, _ = b.Write(targetBytes) return b.Bytes() } diff --git a/reparse_lx_test.go b/reparse_lx_test.go index d4a5f14..f0c9c4c 100644 --- a/reparse_lx_test.go +++ b/reparse_lx_test.go @@ -6,10 +6,17 @@ import ( "testing" ) +const ( + testLxSymlinkAbsolutePath = "/usr/bin/bash" + testWindowsSymlinkPath = `C:\Windows\System32` + testLxSymlinkRelativePath = "../bin/sh" + testLxSymlinkSpecialCharsPath = "/path/with spaces/and-special!@#$%/файл.txt" +) + func TestLxSymlinkRoundTrip(t *testing.T) { // Test LX symlink encode/decode original := &ReparsePoint{ - Target: "/usr/bin/bash", + Target: testLxSymlinkAbsolutePath, IsMountPoint: false, IsLxSymlink: true, } @@ -38,7 +45,7 @@ func TestLxSymlinkRoundTrip(t *testing.T) { func TestWindowsSymlinkNotLx(t *testing.T) { // Test that regular Windows symlinks are not marked as LX original := &ReparsePoint{ - Target: `C:\Windows\System32`, + Target: testWindowsSymlinkPath, IsMountPoint: false, IsLxSymlink: false, } @@ -57,3 +64,89 @@ func TestWindowsSymlinkNotLx(t *testing.T) { t.Errorf("Windows symlink incorrectly marked as LX symlink") } } + +func TestLxSymlinkEmptyTarget(t *testing.T) { + // Test LX symlink with empty target + original := &ReparsePoint{ + Target: "", + IsMountPoint: false, + IsLxSymlink: true, + } + + // Encode + encoded := EncodeReparsePoint(original) + + // Decode + decoded, err := DecodeReparsePoint(encoded) + if err != nil { + t.Fatalf("Failed to decode: %v", err) + } + + // Verify + if decoded.Target != original.Target { + t.Errorf("Target mismatch: got %q, want %q", decoded.Target, original.Target) + } + if !decoded.IsLxSymlink { + t.Errorf("IsLxSymlink should be true") + } +} + +func TestLxSymlinkRelativePath(t *testing.T) { + // Test LX symlink with relative path + original := &ReparsePoint{ + Target: testLxSymlinkRelativePath, + IsMountPoint: false, + IsLxSymlink: true, + } + + // Encode + encoded := EncodeReparsePoint(original) + + // Decode + decoded, err := DecodeReparsePoint(encoded) + if err != nil { + t.Fatalf("Failed to decode: %v", err) + } + + // Verify + if decoded.Target != original.Target { + t.Errorf("Target mismatch: got %q, want %q", decoded.Target, original.Target) + } + if !decoded.IsLxSymlink { + t.Errorf("IsLxSymlink should be true") + } +} + +func TestLxSymlinkSpecialCharacters(t *testing.T) { + // Test LX symlink with special characters and Unicode + original := &ReparsePoint{ + Target: testLxSymlinkSpecialCharsPath, + IsMountPoint: false, + IsLxSymlink: true, + } + + // Encode + encoded := EncodeReparsePoint(original) + + // Decode + decoded, err := DecodeReparsePoint(encoded) + if err != nil { + t.Fatalf("Failed to decode: %v", err) + } + + // Verify + if decoded.Target != original.Target { + t.Errorf("Target mismatch: got %q, want %q", decoded.Target, original.Target) + } + if !decoded.IsLxSymlink { + t.Errorf("IsLxSymlink should be true") + } +} + +func TestEncodeReparsePointNil(t *testing.T) { + // Test encoding a nil ReparsePoint + encoded := EncodeReparsePoint(nil) + if encoded != nil { + t.Errorf("Expected nil result for nil input, got %v", encoded) + } +}