static extern bool SetLxssEa(SafeFileHandle hFile, LxssEaData data, int dataLength);
public static void ExtractTar(Stream stream, string tarRootPath, string targetPath) { targetPath = targetPath.ToExactPath(); Utils.Log($"Extracting the tar file to \"{targetPath}\"."); using (var tar = new TarInputStream(stream)) { while (true) { var entry = tar.GetNextEntry(); if (entry == null) { break; } var type = entry.TarHeader.TypeFlag; var newFilePath = entry.Name.StripRootPath(tarRootPath); if (newFilePath == null) { continue; } newFilePath = Path.Combine(targetPath, newFilePath.ToWslPath()); if (type == TarHeader.LF_LINK) { var linkTargetPath = entry.TarHeader.LinkName.StripRootPath(tarRootPath); if (linkTargetPath == null) { Utils.Warning($"Igoring the hard link \"{newFilePath}\" to \"{entry.TarHeader.LinkName}\", which points to a location out of the specified root directory."); continue; } linkTargetPath = Path.Combine(targetPath, linkTargetPath.ToWslPath()); using (var hTarget = GetFileHandle(linkTargetPath.ToNtPath(), false, false, false)) { CheckFileHandle(hTarget, linkTargetPath); if (!MakeHardLink(hTarget, newFilePath.ToNtPath())) { Utils.Error($"Couldn't create the hard link from \"{newFilePath}\" to \"{linkTargetPath}\"."); } } } else { using (var hNew = GetFileHandle(newFilePath.ToNtPath(), type == TarHeader.LF_DIR, true, true)) { CheckFileHandle(hNew, newFilePath); var eaData = new LxssEaData { Mode = entry.TarHeader.Mode, Uid = entry.UserId, Gid = entry.GroupId }; DateTimeOffset modTime = DateTime.SpecifyKind(entry.ModTime, DateTimeKind.Utc); eaData.Atime = eaData.Mtime = eaData.Ctime = modTime.ToUnixTimeSeconds(); switch (type) { case TarHeader.LF_DIR: eaData.Mode |= 0x4000; break; case TarHeader.LF_SYMLINK: eaData.Mode |= 0xa000; break; case TarHeader.LF_OLDNORM: goto case TarHeader.LF_NORMAL; case TarHeader.LF_NORMAL: eaData.Mode |= 0x8000; break; default: Utils.Warning($"Ignoring the file \"{entry.Name}\" of unsupported file type '{(char)type}'."); continue; } if (!SetLxssEa(hNew, eaData, Marshal.SizeOf(typeof(LxssEaData)))) { Utils.Error($"Couldn't set extended attributes of \"{newFilePath}\"."); } if (type == TarHeader.LF_DIR) { continue; } using (var fsNew = new FileStream(hNew, FileAccess.Write)) { if (entry.TarHeader.TypeFlag == TarHeader.LF_SYMLINK) { var linkData = Encoding.UTF8.GetBytes(entry.TarHeader.LinkName); fsNew.Write(linkData, 0, linkData.Length); } else { tar.CopyEntryContents(fsNew); } } } } } } }