Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Get Unix file stats with LStat (instead of Stat)
Browse files Browse the repository at this point in the history
Stat was ignoring symbolic links (and getting stats for the target
instead) which caused checks for whether or not a path was a sym link
to fail on Unix.

Fixes dotnet/corefx#5015
  • Loading branch information
mjrousos committed Jan 14, 2016
1 parent 628384e commit 75dedd7
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 34 deletions.
13 changes: 0 additions & 13 deletions src/Common/tests/System/IO/FileCleanupTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,6 @@ protected string GetTestFilePath(int? index = null, [CallerMemberName] string me
return Path.Combine(TestDirectory, GetTestFileName(index, memberName, lineNumber));
}

/// <summary>
/// Creates a non-empty file
/// </summary>
/// <param name="path">Path to create the file at</param>
protected void CreateNonEmptyFile(string path, int fileSize)
{
using (var fs = File.Create(path))
{
var testData = new byte[fileSize];
fs.Write(testData, 0, testData.Length);
}
}

/// <summary>Gets a test file name that is associated with the call site.</summary>
/// <param name="index">An optional index value to use as a suffix on the file name. Typically a loop index.</param>
/// <param name="memberName">The member name of the function calling this method.</param>
Expand Down
2 changes: 1 addition & 1 deletion src/System.IO.FileSystem/src/System/IO/UnixFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public override void CopyFile(string sourceFullPath, string destFullPath, bool o
}

// Now copy over relevant read/write/execute permissions from the source to the destination
Interop.Sys.FileStatus status;
// Use Stat (not LStat) since permissions for symbolic links are meaninless and defer to permissions on the target
Interop.Sys.FileStatus status;
Interop.CheckIo(Interop.Sys.Stat(sourceFullPath, out status), sourceFullPath);
int newMode = status.Mode & (int)Interop.Sys.Permissions.Mask;
Interop.CheckIo(Interop.Sys.ChMod(destFullPath, newMode), destFullPath);
Expand Down
28 changes: 23 additions & 5 deletions src/System.IO.FileSystem/tests/File/GetSetAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,24 +102,29 @@ public void WindowsInvalidAttributes(FileAttributes attr)
Assert.Equal(FileAttributes.Normal, Get(path));
}

[Fact]
// In some cases (such as when running without elevated privileges,
// the symbolic link may fail to create. Only run this test if it creates
// links successfully.
[ConditionalFact("CanCreateSymbolicLinks")]
public void SymLinksAreReparsePoints()
{
var path = GetTestFilePath();
var linkPath = GetTestFilePath();
File.Create(path).Dispose();
MountHelper.CreateSymbolicLink(linkPath, path);

Assert.True(MountHelper.CreateSymbolicLink(linkPath, path));
Assert.Equal(FileAttributes.ReparsePoint, FileAttributes.ReparsePoint & Get(linkPath));
}

[Fact]
// In some cases (such as when running without elevated privileges,
// the symbolic link may fail to create. Only run this test if it creates
// links successfully.
[ConditionalFact("CanCreateSymbolicLinks")]
public void SymLinksDoNotReflectTargetAttributes()
{
var path = GetTestFilePath();
var linkPath = GetTestFilePath();
File.Create(path).Dispose();
MountHelper.CreateSymbolicLink(linkPath, path);
Assert.True(MountHelper.CreateSymbolicLink(linkPath, path));

Set(path, FileAttributes.ReadOnly);

Expand All @@ -130,5 +135,18 @@ public void SymLinksDoNotReflectTargetAttributes()
Assert.Equal(FileAttributes.ReparsePoint, FileAttributes.ReparsePoint & Get(linkPath));
Assert.Equal((FileAttributes)0, FileAttributes.ReadOnly & Get(linkPath));
}

private static bool CanCreateSymbolicLinks
{
get
{
var path = Path.GetTempFileName();
var linkPath = path + ".link";
var ret = MountHelper.CreateSymbolicLink(linkPath, path);
try { File.Delete(path); } catch { }
try { File.Delete(linkPath); } catch { }
return ret;
}
}
}
}
20 changes: 18 additions & 2 deletions src/System.IO.FileSystem/tests/FileInfo/Exists.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,35 @@ public void FalseForDirectory()
Assert.False(di.Exists);
}

[Fact]
// In some cases (such as when running without elevated privileges,
// the symbolic link may fail to create. Only run this test if it creates
// links successfully.
[ConditionalFact("CanCreateSymbolicLinks")]
public void SymLinksExistIndependentlyOfTarget()
{
var path = GetTestFilePath();
var linkPath = GetTestFilePath();
File.Create(path).Dispose();
MountHelper.CreateSymbolicLink(linkPath, path);
Assert.True(MountHelper.CreateSymbolicLink(linkPath, path));
File.Delete(path);

var info = new FileInfo(path);
var linkInfo = new FileInfo(linkPath);
Assert.True(linkInfo.Exists);
Assert.False(info.Exists);
}

private static bool CanCreateSymbolicLinks
{
get
{
var path = Path.GetTempFileName();
var linkPath = path + ".link";
var ret = MountHelper.CreateSymbolicLink(linkPath, path);
try { File.Delete(path); } catch { }
try { File.Delete(linkPath); } catch { }
return ret;
}
}
}
}
38 changes: 28 additions & 10 deletions src/System.IO.FileSystem/tests/FileInfo/Length.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,39 @@ public void Length_Of_Directory_Throws_FileNotFoundException()
Assert.Throws<FileNotFoundException>(() => info.Length);
}

[Fact]
// In some cases (such as when running without elevated privileges,
// the symbolic link may fail to create. Only run this test if it creates
// links successfully.
[ConditionalFact("CanCreateSymbolicLinks")]
public void SymLinkLength()
{
var path = GetTestFilePath();
var linkPath = GetTestFilePath();
CreateNonEmptyFile(path, 500);
MountHelper.CreateSymbolicLink(linkPath, path);
using (var tempFile = new TempFile(path, 2000))
{
Assert.True(MountHelper.CreateSymbolicLink(linkPath, path));

var info = new FileInfo(path);
var linkInfo = new FileInfo(linkPath);
Assert.Equal(2000, info.Length);
// On Windows, sym links report 0 size; on Linux, their size is the length of the path they point to
// Confirm that the size we get is not the size of the target file (and that it's less, since our temporary
// sym links should never exceed 500 bytes.
Assert.True(2000 > linkInfo.Length);
}
}

var info = new FileInfo(path);
var linkInfo = new FileInfo(linkPath);
Assert.Equal(500, info.Length);
// On Windows, sym links report 0 size; on Linux, their size is the length of the path they point to
// Confirm that the size we get is not the size of the target file (and that it's less, since our temporary
// sym links should never exceed 500 bytes.
Assert.True(500 > linkInfo.Length);
private static bool CanCreateSymbolicLinks
{
get
{
var path = Path.GetTempFileName();
var linkPath = path + ".link";
var ret = MountHelper.CreateSymbolicLink(linkPath, path);
try { File.Delete(path); } catch { }
try { File.Delete(linkPath); } catch { }
return ret;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public static class MountHelper
/// <summary>Creates a symbolic link using command line tools</summary>
/// <param name="linkPath">The existing file</param>
/// <param name="targetPath"></param>
public static int CreateSymbolicLink(string linkPath, string targetPath)
public static bool CreateSymbolicLink(string linkPath, string targetPath)
{
Process symLinkProcess = null;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
Expand All @@ -46,11 +46,11 @@ public static int CreateSymbolicLink(string linkPath, string targetPath)
if (symLinkProcess != null)
{
symLinkProcess.WaitForExit();
return symLinkProcess.ExitCode;
return (0 == symLinkProcess.ExitCode);
}
else
{
return -1;
return false;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@
<Compile Include="$(CommonTestPath)\System\IO\FileCleanupTestBase.cs">
<Link>Common\System\IO\FileCleanupTestBase.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)\System\IO\TempFile.cs">
<Link>Common\System\IO\TempFile.cs</Link>
</Compile>
<!-- Performance Tests -->
<Compile Include="Performance\Perf.Directory.cs" />
<Compile Include="Performance\Perf.File.cs" />
Expand Down

0 comments on commit 75dedd7

Please sign in to comment.