-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tar: Only treat reparse points marked as junctions or symlinks as actual tar symlinks #89102
Changes from 6 commits
507f169
326846a
689064c
417585a
5348435
ddd8c8f
53e2ad8
9d17d9c
e934e76
375f1b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,8 +3,6 @@ | |
|
||
using System.Diagnostics; | ||
using System.IO; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace System.Formats.Tar | ||
{ | ||
|
@@ -21,18 +19,32 @@ private TarEntry ConstructEntryForWriting(string fullPath, string entryName, Fil | |
|
||
FileAttributes attributes = File.GetAttributes(fullPath); | ||
|
||
bool isDirectory = (attributes & FileAttributes.Directory) != 0; | ||
|
||
Interop.Kernel32.WIN32_FIND_DATA data = default; | ||
Interop.Kernel32.GetFindData(fullPath, isDirectory, ignoreAccessDenied: false, ref data); | ||
|
||
TarEntryType entryType; | ||
if ((attributes & FileAttributes.ReparsePoint) != 0) | ||
{ | ||
entryType = TarEntryType.SymbolicLink; | ||
if (data.dwReserved0 is Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_SYMLINK or | ||
Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT) | ||
Comment on lines
+30
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks like another data point in favor of having an API for ReparseTags #1908. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. |
||
{ | ||
entryType = TarEntryType.SymbolicLink; | ||
} | ||
else | ||
{ | ||
// Treat any other reparse point as regular file | ||
entryType = TarHelpers.GetRegularFileEntryTypeForFormat(Format); | ||
} | ||
} | ||
else if ((attributes & FileAttributes.Directory) != 0) | ||
else if (isDirectory) | ||
{ | ||
entryType = TarEntryType.Directory; | ||
} | ||
else if ((attributes & (FileAttributes.Normal | FileAttributes.Archive)) != 0) | ||
{ | ||
entryType = Format is TarEntryFormat.V7 ? TarEntryType.V7RegularFile : TarEntryType.RegularFile; | ||
entryType = TarHelpers.GetRegularFileEntryTypeForFormat(Format); | ||
} | ||
else | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.IO; | ||
using Xunit; | ||
|
||
namespace System.Formats.Tar.Tests; | ||
|
||
public partial class TarWriter_WriteEntry_File_Tests : TarWriter_File_Base | ||
{ | ||
[Theory] | ||
[InlineData(TarEntryFormat.V7)] | ||
[InlineData(TarEntryFormat.Ustar)] | ||
[InlineData(TarEntryFormat.Pax)] | ||
[InlineData(TarEntryFormat.Gnu)] | ||
public void Add_Junction_As_SymbolicLink(TarEntryFormat format) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you run these tests without elevation? I think it's missing a can create symlinks condition. I've added them a few times when tests failed locally. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Starting with Windows 10 Insiders build 14972, symlinks can be created without needing to elevate the console as administrator. https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10/ If we still have tests running older Windows versions, they should break in the CI. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Junctions are ancient, they don't require elevation AFAIK. They ran without problem in my local machine. The CI should also cry if something goes wrong. This new test does not create symlinks in the disk by the way, it adds an entry to the tar archive as a symlink. The only thing that gets created in disk is the junction. |
||
{ | ||
using TempDirectory root = new TempDirectory(); | ||
string targetName = "TargetDirectory"; | ||
string junctionName = "JunctionDirectory"; | ||
string targetPath = Path.Join(root.Path, targetName); | ||
string junctionPath = Path.Join(root.Path, junctionName); | ||
|
||
Directory.CreateDirectory(targetPath); | ||
|
||
Assert.True(MountHelper.CreateJunction(junctionPath, targetPath)); | ||
DirectoryInfo junctionInfo = new(junctionPath); | ||
|
||
using MemoryStream archive = new MemoryStream(); | ||
using (TarWriter writer = new TarWriter(archive, format, leaveOpen: true)) | ||
{ | ||
writer.WriteEntry(fileName: junctionPath, entryName: junctionPath); | ||
} | ||
|
||
archive.Position = 0; | ||
using (TarReader reader = new TarReader(archive)) | ||
{ | ||
TarEntry entry = reader.GetNextEntry(); | ||
Assert.Equal(format, entry.Format); | ||
|
||
Assert.NotNull(entry); | ||
Assert.Equal(junctionPath, entry.Name); | ||
Assert.Equal(targetPath, entry.LinkName); | ||
Assert.Equal(TarEntryType.SymbolicLink, entry.EntryType); | ||
Assert.Null(entry.DataStream); | ||
|
||
VerifyPlatformSpecificMetadata(junctionPath, entry); | ||
|
||
Assert.Null(reader.GetNextEntry()); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.IO; | ||
using System.Threading.Tasks; | ||
using Xunit; | ||
|
||
namespace System.Formats.Tar.Tests; | ||
|
||
public partial class TarWriter_WriteEntryAsync_File_Tests : TarWriter_File_Base | ||
{ | ||
[Theory] | ||
[InlineData(TarEntryFormat.V7)] | ||
[InlineData(TarEntryFormat.Ustar)] | ||
[InlineData(TarEntryFormat.Pax)] | ||
[InlineData(TarEntryFormat.Gnu)] | ||
public async Task Add_Junction_As_SymbolicLink_Async(TarEntryFormat format) | ||
{ | ||
using TempDirectory root = new TempDirectory(); | ||
string targetName = "TargetDirectory"; | ||
string junctionName = "JunctionDirectory"; | ||
string targetPath = Path.Join(root.Path, targetName); | ||
string junctionPath = Path.Join(root.Path, junctionName); | ||
|
||
Directory.CreateDirectory(targetPath); | ||
|
||
Assert.True(MountHelper.CreateJunction(junctionPath, targetPath)); | ||
DirectoryInfo junctionInfo = new(junctionPath); | ||
|
||
await using MemoryStream archive = new MemoryStream(); | ||
await using (TarWriter writer = new TarWriter(archive, format, leaveOpen: true)) | ||
{ | ||
await writer.WriteEntryAsync(fileName: junctionPath, entryName: junctionPath); | ||
} | ||
|
||
archive.Position = 0; | ||
await using (TarReader reader = new TarReader(archive)) | ||
{ | ||
TarEntry entry = await reader.GetNextEntryAsync(); | ||
Assert.Equal(format, entry.Format); | ||
|
||
Assert.NotNull(entry); | ||
Assert.Equal(junctionPath, entry.Name); | ||
Assert.Equal(targetPath, entry.LinkName); | ||
Assert.Equal(TarEntryType.SymbolicLink, entry.EntryType); | ||
Assert.Null(entry.DataStream); | ||
|
||
VerifyPlatformSpecificMetadata(junctionPath, entry); | ||
|
||
Assert.Null(await reader.GetNextEntryAsync()); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be called only when the file is a reparse point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right.