m_extraction_dir = extractor.extraction_dir();
// Determine if embedded files are already extracted, and available for reuse
- if (extractor.can_reuse_extraction())
+ if (!extractor.can_reuse_extraction())
{
- return StatusCode::Success;
- }
-
- manifest_t manifest = manifest_t::read(reader, header.num_embedded_files());
+ manifest_t manifest = manifest_t::read(reader, header.num_embedded_files());
- extractor.extract(manifest, reader);
+ extractor.extract(manifest, reader);
+ }
unmap_host();
int fd = open(path.c_str(), O_RDONLY, (S_IRUSR | S_IRGRP | S_IROTH));
if (fd == -1)
{
- trace::warning(_X("Failed to map file. open(%s) failed with error %d"), path.c_str(), errno);
+ trace::error(_X("Failed to map file. open(%s) failed with error %d"), path.c_str(), errno);
return nullptr;
}
struct stat buf;
if (fstat(fd, &buf) != 0)
{
- trace::warning(_X("Failed to map file. fstat(%s) failed with error %d"), path.c_str(), errno);
+ trace::error(_X("Failed to map file. fstat(%s) failed with error %d"), path.c_str(), errno);
close(fd);
return nullptr;
}
if(address == nullptr)
{
- trace::warning(_X("Failed to map file. mmap(%s) failed with error %d"), path.c_str(), errno);
+ trace::error(_X("Failed to map file. mmap(%s) failed with error %d"), path.c_str(), errno);
close(fd);
return nullptr;
}
if (file == INVALID_HANDLE_VALUE)
{
- trace::warning(_X("Failed to map file. CreateFileW(%s) failed with error %d"), path.c_str(), GetLastError());
+ trace::error(_X("Failed to map file. CreateFileW(%s) failed with error %d"), path.c_str(), GetLastError());
return nullptr;
}
LARGE_INTEGER fileSize;
if (GetFileSizeEx(file, &fileSize) == 0)
{
- trace::warning(_X("Failed to map file. GetFileSizeEx(%s) failed with error %d"), path.c_str(), GetLastError());
+ trace::error(_X("Failed to map file. GetFileSizeEx(%s) failed with error %d"), path.c_str(), GetLastError());
CloseHandle(file);
return nullptr;
}
if (map == NULL)
{
- trace::warning(_X("Failed to map file. CreateFileMappingW(%s) failed with error %d"), path.c_str(), GetLastError());
+ trace::error(_X("Failed to map file. CreateFileMappingW(%s) failed with error %d"), path.c_str(), GetLastError());
CloseHandle(file);
return nullptr;
}
void *address = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
- if (map == NULL)
+ if (address == NULL)
{
- trace::warning(_X("Failed to map file. MapViewOfFile(%s) failed with error %d"), path.c_str(), GetLastError());
- CloseHandle(file);
- return nullptr;
+ trace::error(_X("Failed to map file. MapViewOfFile(%s) failed with error %d"), path.c_str(), GetLastError());
}
+ // The file-handle (file) and mapping object handle (map) can be safely closed
+ // once the file is mapped. The OS keeps the file open if there is an open mapping into the file.
+
+ CloseHandle(map);
+ CloseHandle(file);
+
return address;
}
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>$(NETCoreAppFramework)</TargetFramework>
+ <OutputType>Exe</OutputType>
+ <RuntimeIdentifier>$(TestTargetRid)</RuntimeIdentifier>
+ <RuntimeFrameworkVersion>$(MNAVersion)</RuntimeFrameworkVersion>
+ </PropertyGroup>
+
+</Project>
--- /dev/null
+using System;
+using System.IO;
+using System.Threading;
+
+namespace AppWithSubDirs
+{
+ public static class Program
+ {
+ public static void Main(string[] args)
+ {
+ Console.Write("Hello ");
+
+ // If the caller wants the app to start and wait,
+ // it provides the name of a lock-file to write.
+ // In this case, this test app creates the lock file
+ // and waits until the file is deleted.
+ if (args.Length > 0)
+ {
+ string writeFile = args[0];
+
+ var fs = File.Create(writeFile);
+ fs.Close();
+
+ Thread.Sleep(200);
+
+ while (File.Exists(writeFile))
+ {
+ Thread.Sleep(100);
+ }
+ }
+
+ Console.WriteLine("World!");
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.IO;
+using Xunit;
+using Microsoft.DotNet.Cli.Build.Framework;
+using Microsoft.DotNet.CoreSetup.Test;
+using BundleTests.Helpers;
+using System.Threading;
+
+namespace AppHost.Bundle.Tests
+{
+ public class BundleRename : IClassFixture<BundleRename.SharedTestState>
+ {
+ private SharedTestState sharedTestState;
+
+ public BundleRename(SharedTestState fixture)
+ {
+ sharedTestState = fixture;
+ }
+
+ [Theory]
+ [InlineData(true)] // Test renaming the single-exe during the initial run, when contents are extracted
+ [InlineData(false)] // Test renaming the single-exe during subsequent runs, when contents are reused
+ private void Bundle_can_be_renamed_while_running(bool renameFirstRun)
+ {
+ var fixture = sharedTestState.TestFixture.Copy();
+ string singleFile = BundleHelper.GetPublishedSingleFilePath(fixture);
+ string renameFile = Path.Combine(BundleHelper.GetPublishPath(fixture), Path.GetRandomFileName());
+ string writeFile = Path.Combine(BundleHelper.GetPublishPath(fixture), "lock");
+
+ if (!renameFirstRun)
+ {
+ Command.Create(singleFile)
+ .CaptureStdErr()
+ .CaptureStdOut()
+ .Execute()
+ .Should()
+ .Pass()
+ .And
+ .HaveStdOutContaining("Hello World!");
+ }
+
+ var singleExe = Command.Create(singleFile, writeFile)
+ .CaptureStdErr()
+ .CaptureStdOut()
+ .Start();
+
+ // Once the App starts running, it creates the writeFile, and waits until the file is deleted.
+ while (!File.Exists(writeFile))
+ {
+ Thread.Sleep(100);
+ }
+
+ File.Move(singleFile, renameFile);
+ File.Delete(writeFile);
+
+ var result = singleExe.WaitForExit(fExpectedToFail: false);
+
+ result
+ .Should()
+ .Pass()
+ .And
+ .HaveStdOutContaining("Hello World!");
+ }
+
+ public class SharedTestState : IDisposable
+ {
+ public TestProjectFixture TestFixture { get; set; }
+ public RepoDirectoriesProvider RepoDirectories { get; set; }
+
+ public SharedTestState()
+ {
+ RepoDirectories = new RepoDirectoriesProvider();
+ TestFixture = new TestProjectFixture("AppWithWait", RepoDirectories);
+ TestFixture
+ .EnsureRestoredForRid(TestFixture.CurrentRid, RepoDirectories.CorehostPackages)
+ .PublishProject(runtime: TestFixture.CurrentRid,
+ singleFile: true,
+ outputDirectory: BundleHelper.GetPublishPath(TestFixture));
+ }
+
+ public void Dispose()
+ {
+ TestFixture.Dispose();
+ }
+ }
+ }
+}
return Path.Combine(GetPublishPath(fixture), GetAppName(fixture));
}
+ public static string GetPublishedSingleFilePath(TestProjectFixture fixture)
+ {
+ return GetHostPath(fixture);
+ }
+
public static string GetHostName(TestProjectFixture fixture)
{
return Path.GetFileName(fixture.TestProject.AppExe);
using System;
using System.Collections.Generic;
using System.IO;
-using System.Text;
namespace Microsoft.DotNet.CoreSetup.Test
{
string runtime = null,
string framework = null,
string selfContained = null,
- string outputDirectory = null)
+ string outputDirectory = null,
+ bool singleFile = false)
{
dotnet = dotnet ?? SdkDotnet;
outputDirectory = outputDirectory ?? TestProject.OutputDirectory;
publishArgs.Add(outputDirectory);
}
+ if (singleFile)
+ {
+ publishArgs.Add("/p:PublishSingleFile=true");
+ }
+
publishArgs.Add($"/p:TestTargetRid={RepoDirProvider.TargetRID}");
publishArgs.Add($"/p:MNAVersion={RepoDirProvider.MicrosoftNETCoreAppVersion}");