Skip to content

Handle absolute paths - #10

Open
PenguinKeeper7 wants to merge 2 commits into
acmesecorg:mainfrom
PenguinKeeper7:main
Open

Handle absolute paths#10
PenguinKeeper7 wants to merge 2 commits into
acmesecorg:mainfrom
PenguinKeeper7:main

Conversation

@PenguinKeeper7

Copy link
Copy Markdown
Contributor

Avoid errors with Directory.GetFiles when specifying an absolute path. Fixed error:

Unhandled exception. System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.ArgumentException: Second path fragment must not be a drive or UNC name. (Parameter 'expression')

Avoid errors with Directory.GetFiles when specifying an absolute path. Old error:
```
Unhandled exception. System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.ArgumentException: Second path fragment must not be a drive or UNC name. (Parameter 'expression')
```
@PenguinKeeper7 PenguinKeeper7 changed the title Add implementation for both path types Handle absolute paths Dec 31, 2022
Fold slashes to / instead of \ for Linux compatibility

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request attempts to fix an error that occurs when specifying absolute paths to Directory.GetFiles, which previously threw an ArgumentException stating "Second path fragment must not be a drive or UNC name." The change adds logic to detect and handle absolute paths separately from relative paths.

Changes:

  • Added absolute path detection using Path.IsPathFullyQualified
  • Implemented path splitting logic to separate directory from search pattern for absolute paths
  • Minor formatting corrections (pragma directive alignment and trailing whitespace removal)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread CatalogPlugin.cs
Comment on lines +23 to +26
string path = options.InputPath.Replace("\\", "/");
int pos = path.LastIndexOf('/');

if (File.Exists(options.InputPath) || Directory.Exists(options.InputPath))

Copilot AI Jan 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The absolute path handling lacks validation for path traversal attacks. An absolute path could potentially include ".." sequences that allow accessing files outside intended directories. Consider using Path.GetFullPath to normalize and validate the path before processing.

Suggested change
string path = options.InputPath.Replace("\\", "/");
int pos = path.LastIndexOf('/');
if (File.Exists(options.InputPath) || Directory.Exists(options.InputPath))
string fullPath;
try
{
// Normalize the path to eliminate any relative segments
fullPath = Path.GetFullPath(options.InputPath);
}
catch (Exception)
{
WriteError($"Input path {options.InputPath} is invalid.");
return;
}
// Prevent directory traversal via parent-directory segments
if (options.InputPath.Contains(".."))
{
WriteError("Parent directory segments (..) are not allowed in the input path.");
return;
}
string path = fullPath.Replace("\\", "/");
int pos = path.LastIndexOf('/');
if (File.Exists(fullPath) || Directory.Exists(fullPath))

Copilot uses AI. Check for mistakes.
Comment thread CatalogPlugin.cs
Comment on lines +23 to 32
string path = options.InputPath.Replace("\\", "/");
int pos = path.LastIndexOf('/');

if (File.Exists(options.InputPath) || Directory.Exists(options.InputPath))
fileEntries = Directory.GetFiles(path[..pos], path[(pos + 1)..], SearchOption.AllDirectories);
}
//Relative path
else
fileEntries = Directory.GetFiles(currentDirectory, options.InputPath, SearchOption.AllDirectories);

Copilot AI Jan 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic for handling absolute paths has several issues. First, if the path doesn't exist (line 26 check fails), fileEntries will remain as an empty array but execution continues, which differs from the relative path behavior. Second, the path splitting logic assumes the InputPath contains at least one path separator, but a fully qualified path like "C:" would cause LastIndexOf to return -1, leading to incorrect range operations on line 27. Third, if InputPath is a directory path (not a file pattern), the split logic will incorrectly separate the directory name from its parent.

Suggested change
string path = options.InputPath.Replace("\\", "/");
int pos = path.LastIndexOf('/');
if (File.Exists(options.InputPath) || Directory.Exists(options.InputPath))
fileEntries = Directory.GetFiles(path[..pos], path[(pos + 1)..], SearchOption.AllDirectories);
}
//Relative path
else
fileEntries = Directory.GetFiles(currentDirectory, options.InputPath, SearchOption.AllDirectories);
// If it's an existing file, just process that single file
if (File.Exists(options.InputPath))
{
fileEntries = new[] { options.InputPath };
}
// If it's an existing directory, search all files within it
else if (Directory.Exists(options.InputPath))
{
fileEntries = Directory.GetFiles(options.InputPath, "*", SearchOption.AllDirectories);
}
else
{
// Treat as a pattern with directory and file mask components
var directoryPart = Path.GetDirectoryName(options.InputPath);
var patternPart = Path.GetFileName(options.InputPath);
// If there is no directory part, the pattern is not rooted anywhere valid
if (string.IsNullOrEmpty(directoryPart))
{
WriteError($"Input path {options.InputPath} was not found.");
return;
}
if (!Directory.Exists(directoryPart))
{
WriteError($"Input folder {directoryPart} was not found.");
return;
}
// If no explicit pattern, default to all files
if (string.IsNullOrEmpty(patternPart))
{
patternPart = "*";
}
fileEntries = Directory.GetFiles(directoryPart, patternPart, SearchOption.AllDirectories);
}
}
//Relative path
else
{
fileEntries = Directory.GetFiles(currentDirectory, options.InputPath, SearchOption.AllDirectories);
}

Copilot uses AI. Check for mistakes.
Comment thread CatalogPlugin.cs
Comment on lines +23 to +27
string path = options.InputPath.Replace("\\", "/");
int pos = path.LastIndexOf('/');

if (File.Exists(options.InputPath) || Directory.Exists(options.InputPath))
fileEntries = Directory.GetFiles(path[..pos], path[(pos + 1)..], SearchOption.AllDirectories);

Copilot AI Jan 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The path normalization using Replace on line 23 is used to find the last path separator, but the original options.InputPath is used for File.Exists and Directory.Exists checks on line 26. This creates an inconsistency where the normalized path is parsed but the original path is checked for existence. If the original path uses backslashes and refers to a directory, the logic may fail to correctly identify the directory vs pattern components.

Suggested change
string path = options.InputPath.Replace("\\", "/");
int pos = path.LastIndexOf('/');
if (File.Exists(options.InputPath) || Directory.Exists(options.InputPath))
fileEntries = Directory.GetFiles(path[..pos], path[(pos + 1)..], SearchOption.AllDirectories);
string directoryPath;
string searchPattern;
// If the input path is an existing directory, search for all .txt files under it.
if (Directory.Exists(options.InputPath))
{
directoryPath = options.InputPath;
searchPattern = "*.txt";
}
else
{
directoryPath = Path.GetDirectoryName(options.InputPath) ?? string.Empty;
searchPattern = Path.GetFileName(options.InputPath);
}
if (!string.IsNullOrEmpty(directoryPath) &&
!string.IsNullOrEmpty(searchPattern) &&
Directory.Exists(directoryPath))
{
fileEntries = Directory.GetFiles(directoryPath, searchPattern, SearchOption.AllDirectories);
}

Copilot uses AI. Check for mistakes.
Comment thread CatalogPlugin.cs
Comment on lines +26 to +27
if (File.Exists(options.InputPath) || Directory.Exists(options.InputPath))
fileEntries = Directory.GetFiles(path[..pos], path[(pos + 1)..], SearchOption.AllDirectories);

Copilot AI Jan 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When File.Exists or Directory.Exists returns false on line 26, the condition fails but fileEntries remains as an empty array without any error message or alternative handling. This silent failure makes debugging difficult for users who provide an absolute path that doesn't exist, as they won't get the "No .txt files found" error until line 34, which may be misleading.

Suggested change
if (File.Exists(options.InputPath) || Directory.Exists(options.InputPath))
fileEntries = Directory.GetFiles(path[..pos], path[(pos + 1)..], SearchOption.AllDirectories);
if (File.Exists(options.InputPath) || Directory.Exists(options.InputPath))
{
fileEntries = Directory.GetFiles(path[..pos], path[(pos + 1)..], SearchOption.AllDirectories);
}
else
{
WriteError($"Input path {options.InputPath} was not found.");
return;
}

Copilot uses AI. Check for mistakes.
Comment thread CatalogPlugin.cs
Comment on lines +23 to +27
string path = options.InputPath.Replace("\\", "/");
int pos = path.LastIndexOf('/');

if (File.Exists(options.InputPath) || Directory.Exists(options.InputPath))
fileEntries = Directory.GetFiles(path[..pos], path[(pos + 1)..], SearchOption.AllDirectories);

Copilot AI Jan 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The path splitting logic doesn't correctly handle all absolute path scenarios. If InputPath is an absolute directory path like "C:\Users\data" (without a wildcard pattern), this code splits it into directory="C:\Users" and pattern="data", which will search for files matching "data" pattern in "C:\Users" instead of searching all files in "C:\Users\data". The logic should check if InputPath is a directory and handle it differently from a file pattern.

Suggested change
string path = options.InputPath.Replace("\\", "/");
int pos = path.LastIndexOf('/');
if (File.Exists(options.InputPath) || Directory.Exists(options.InputPath))
fileEntries = Directory.GetFiles(path[..pos], path[(pos + 1)..], SearchOption.AllDirectories);
// If the input is an existing directory, search all files under it.
if (Directory.Exists(options.InputPath))
{
fileEntries = Directory.GetFiles(options.InputPath, "*", SearchOption.AllDirectories);
}
// If the input is an existing file, process just that file.
else if (File.Exists(options.InputPath))
{
fileEntries = new[] { options.InputPath };
}
// Otherwise treat the input as an absolute path containing a file pattern.
else
{
var directory = Path.GetDirectoryName(options.InputPath);
var pattern = Path.GetFileName(options.InputPath);
if (string.IsNullOrEmpty(directory))
{
directory = currentDirectory;
}
fileEntries = Directory.GetFiles(directory, pattern, SearchOption.AllDirectories);
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants