Skip to content

Commit 7bffd84

Browse files
authored
Rn r1078 fix invalid handling of long generated file path lengths (#1079)
* Modified GeneratedFileWriter to support very long file paths on Windows. * Update CHANGELOG.md * Updated method name per review comments. * Updated per review to restore comment in earlier source code commit that was lost. * Modified GeneratedFileWriter such that a call to Path.GetDirectoryName() is invoked on the given input path before modifying it for long-path support in order to avoid possible misbehavior under .NET Framework and older Windows OS versions.
1 parent 4416784 commit 7bffd84

2 files changed

Lines changed: 38 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
* Updated Cucumber dependencies to: Gherkin v39.1.0, Cucumber.Messages v32.0.1 and Cucumber.HtmlFormatter v23.1.0. Formatters.Tests modified by adopting use of Cucumber/CCK (v29.2.2). (#984)
55

66
## Bug fixes:
7+
* Fix: GenerateFeatureFileCodeBehindTask fails with misleading DirectoryNotFoundException when ndjson output path exceeds Windows MAX_PATH (260)
78

8-
*Contributors of this release (in alphabetical order):*
9+
*Contributors of this release (in alphabetical order):* @clrudolphi
910

1011
# v3.3.4 - 2026-03-23
1112

Reqnroll.Tools.MsBuild.Generation/GeneratedFileWriter.cs

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1+
using System;
12
using System.IO;
23
using System.Text;
34
using Reqnroll.Utils;
45

56
namespace Reqnroll.Tools.MsBuild.Generation;
67

7-
/// <summary>
8-
/// This class is going to be obsolete once we implement MsBuild level up-to-date checks.
9-
/// </summary>
108
public class GeneratedFileWriter(IReqnrollTaskLoggingHelper log)
119
{
1210
public void WriteGeneratedFile(string outputPath, string generatedFileContent)
@@ -17,13 +15,15 @@ public void WriteGeneratedFile(string outputPath, string generatedFileContent)
1715

1816
public void DeleteGeneratedFile(string outputPath)
1917
{
20-
if (!File.Exists(outputPath))
18+
var path = ChangePathToSupportLongPaths(outputPath);
19+
20+
if (!File.Exists(path))
2121
return;
2222

2323
log.LogTaskDiagnosticMessage($"Deleting {outputPath}");
2424
try
2525
{
26-
File.Delete(outputPath);
26+
File.Delete(path);
2727
}
2828
catch (IOException ex)
2929
{
@@ -34,12 +34,40 @@ public void DeleteGeneratedFile(string outputPath)
3434
private void WriteFile(string filePath, string content)
3535
{
3636
string directoryPath = Path.GetDirectoryName(filePath);
37-
if (directoryPath != null && !Directory.Exists(directoryPath))
37+
var longDirPath = ChangePathToSupportLongPaths(directoryPath);
38+
if (!string.IsNullOrEmpty(longDirPath) && !Directory.Exists(longDirPath))
39+
{
40+
Directory.CreateDirectory(longDirPath);
41+
}
42+
var longPath = ChangePathToSupportLongPaths(filePath);
43+
WriteAllTextWithRetry(longPath, content, Encoding.UTF8);
44+
}
45+
46+
private static string ChangePathToSupportLongPaths(string path)
47+
{
48+
if (string.IsNullOrWhiteSpace(path))
49+
return path;
50+
51+
string fullPath = Path.GetFullPath(path);
52+
53+
// Cross-platform: only apply extended syntax on Windows.
54+
if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(
55+
System.Runtime.InteropServices.OSPlatform.Windows))
3856
{
39-
Directory.CreateDirectory(directoryPath);
57+
return fullPath;
4058
}
4159

42-
WriteAllTextWithRetry(filePath, content, Encoding.UTF8);
60+
// Already device/extended syntax.
61+
if (fullPath.StartsWith(@"\\?\", StringComparison.Ordinal) ||
62+
fullPath.StartsWith(@"\\.\", StringComparison.Ordinal))
63+
return fullPath;
64+
65+
// UNC longDirPath.
66+
if (fullPath.StartsWith(@"\\", StringComparison.Ordinal))
67+
return @"\\?\UNC\" + fullPath.Substring(2);
68+
69+
// Drive-qualified longDirPath.
70+
return @"\\?\" + fullPath;
4371
}
4472

4573
/// <summary>

0 commit comments

Comments
 (0)