Merge branch 'LazUtils/CreateRelativePath' into 'main'

LazUtils/TryCreateRelativePath: Improved checking for double period (indicating parent folder) in paths

See merge request freepascal.org/lazarus/lazarus!426
This commit is contained in:
Juha Manninen 2025-01-31 19:09:52 +00:00
commit 9d8166766d
2 changed files with 54 additions and 2 deletions

View File

@ -217,7 +217,7 @@ end;
is not threadsafe (at least on Windows platform)
- Dest and Source must either be both absolute filenames, or relative
- Dest and Source cannot contain '..' since no expanding is done by design
- Dest and Source cannot contain '/../' since no expanding is done by design
- Dest and Source must be on same drive or UNC path (Windows)
- if both Dest and Source are relative they must at least share their base directory
- Double PathDelims are ignored (unless they are part of the UNC convention)
@ -298,7 +298,10 @@ var
begin
Result := False;
if (Dest = '') or (Source = '') then Exit;
if (Pos('..',Dest) > 0) or (Pos('..',Source) > 0) then Exit;
// double period components (meaning parent directory) are not allowed in input
if Pos('/../', '/' + SwitchPathDelims(Source, pdsUnix) + '/') > 0 then Exit;
if Pos('/../', '/' + SwitchPathDelims(Dest , pdsUnix) + '/') > 0 then Exit;
SourceRoot := ExtractFileRoot(Source);
DestRoot := ExtractFileRoot(Dest);
//debugln('TryCreaterelativePath: DestRoot = "',DestRoot,'"');

View File

@ -165,6 +165,20 @@ procedure TTestLazFileUtils.TestCreateRelativePath;
CreateRelativePath(Filename,BaseDirectory,UsePointDirectory));
end;
// testing an absolute path and its relative variant
procedure DoTest2(Filename, BaseDirectory, Expected: string;
UsePointDirectory: boolean = false);
begin
// absolute paths
DoTest(Filename, BaseDirectory, Expected, UsePointDirectory);
// relative paths
if Filename = Expected then
Delete(Expected, 1, 1);
Delete(Filename, 1, 1);
Delete(BaseDirectory, 1, 1);
DoTest(Filename, BaseDirectory, Expected);
end;
begin
DoTest('/a','/a','');
DoTest('/a','/a','.',true);
@ -187,8 +201,43 @@ begin
DoTest('/a','/b','/a');
DoTest('~/bin','/','~/bin');
DoTest('$(HOME)/bin','/','$(HOME)/bin');
// single period in file
DoTest2('/dir/file.' , '/dir', 'file.' );
DoTest2('/dir/.file' , '/dir', '.file' );
DoTest2('/dir/.file.' , '/dir', '.file.' );
DoTest2('/dir/file.name', '/dir', 'file.name');
// single period in directory
DoTest2('/dir/dir2./file.txt' , '/dir', 'dir2./file.txt' );
DoTest2('/dir/.dir2/file.txt' , '/dir', '.dir2/file.txt' );
DoTest2('/dir/.dir2./file.txt' , '/dir', '.dir2./file.txt' );
DoTest2('/dir/dir2.name/file.txt', '/dir', 'dir2.name/file.txt');
// double period in file
DoTest2('/dir/file..' , '/dir', 'file..' );
DoTest2('/dir/..file' , '/dir', '..file' );
DoTest2('/dir/..file..' , '/dir', '..file..' );
DoTest2('/dir/file..name', '/dir', 'file..name');
// double period in directory
DoTest2('/dir/dir2../file.txt' , '/dir', 'dir2../file.txt' );
DoTest2('/dir/..dir2/file.txt' , '/dir', '..dir2/file.txt' );
DoTest2('/dir/..dir2../file.txt' , '/dir', '..dir2../file.txt' );
DoTest2('/dir/dir2..name/file.txt', '/dir', 'dir2..name/file.txt');
// triple period (no special purpose)
DoTest2('/dir/dir/...' , '/dir', 'dir/...');
DoTest2('/dir/.../file', '/dir', '.../file');
// illegal input must return the original value
DoTest2('/dir/../file', '/dir' , '/dir/../file');
DoTest2('/dir/..' , '/dir' , '/dir/..' );
DoTest2('/dir/file' , '/dir/../dir', '/dir/file' );
DoTest2('/dir' , '/dir/..' , '/dir' );
DoTest2('/../dir/file', '/../dir' , '/../dir/file');
DoTest2('/dir/file' , '/../' , '/dir/file' );
{$IFDEF MSWindows}
DoTest('D:\a\b\c.pas','D:\a\d\','..\b\c.pas');
// different delimiters
DoTest('D:\dir../file', 'D:\dir..', 'file');
DoTest('D:\dir\../file', 'D:\dir', 'D:\dir\../file');
{$ENDIF}
end;