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

[single-exe] Run from bundle on Windows #26904

Merged
merged 2 commits into from
Sep 27, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/hosts/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ include_directories(inc)
if(WIN32)
add_subdirectory(corerun)
add_subdirectory(coreconsole)
add_subdirectory(corebundle)
add_subdirectory(coreshim)
else(WIN32)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
Expand Down
34 changes: 34 additions & 0 deletions src/coreclr/hosts/bundle/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
set(Bundle_Common_SOURCES
${CMAKE_CURRENT_LIST_DIR}/app_bundle.cpp
${CMAKE_CURRENT_LIST_DIR}/file_entry.cpp
${CMAKE_CURRENT_LIST_DIR}/header.cpp
${CMAKE_CURRENT_LIST_DIR}/manifest.cpp
${CMAKE_CURRENT_LIST_DIR}/marker.cpp
${CMAKE_CURRENT_LIST_DIR}/reader.cpp
${CMAKE_CURRENT_LIST_DIR}/runner.cpp
${CMAKE_CURRENT_LIST_DIR}/utils.cpp
)

set(Bundle_Windows_SOURCES
${Bundle_Common_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/pal_windows.cpp
)

set(Bundle_Unix_SOURCES
${Bundle_Common_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/pal_unix.cpp
)

set(Bundle_HEADERS
${CMAKE_CURRENT_LIST_DIR}/app_bundle.h
${CMAKE_CURRENT_LIST_DIR}/error_codes.h
${CMAKE_CURRENT_LIST_DIR}/file_entry.h
${CMAKE_CURRENT_LIST_DIR}/file_type.h
${CMAKE_CURRENT_LIST_DIR}/header.h
${CMAKE_CURRENT_LIST_DIR}/manifest.h
${CMAKE_CURRENT_LIST_DIR}/marker.h
${CMAKE_CURRENT_LIST_DIR}/pal.h
${CMAKE_CURRENT_LIST_DIR}/reader.h
${CMAKE_CURRENT_LIST_DIR}/runner.h
${CMAKE_CURRENT_LIST_DIR}/utils.h
)
34 changes: 34 additions & 0 deletions src/coreclr/hosts/bundle/app_bundle.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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.

#include "app_bundle.h"
#include "marker.h"
#include "runner.h"

using namespace bundle;

runner_t* app_bundle_t::s_runner = nullptr;

bool app_bundle_t::init(const char* exe_path)
{
if (!bundle::marker_t::is_bundle())
{
return false;
}

pal::string_t self_path;
pal::clr_palstring(exe_path, self_path);

static runner_t runner(exe_path);
s_runner = &runner;

StatusCode status = runner.process();

return status == StatusCode::Success;
}

bool app_bundle_t::probe(const char* path, int64_t* size, int64_t* offset)
{
return s_runner->probe(path, size, offset);
}
28 changes: 28 additions & 0 deletions src/coreclr/hosts/bundle/app_bundle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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.

// This class represents the bundle for the currently executing application
// It is the bundle-processing module's interface with the outside world.

#ifndef __APP_BUNDLE_H__
#define __APP_BUNDLE_H__

#include <stdint.h>

namespace bundle
{
class runner_t;

class app_bundle_t
{
public:
static bool init(const char *path);
static bool probe(const char* path, int64_t* size, int64_t* offset);

private:
static runner_t *s_runner;
};
}

#endif // __APP_BUNDLE_H__
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.

#include "file_entry.h"
#include "trace.h"
#include "error_codes.h"

using namespace bundle;
Expand All @@ -15,7 +14,7 @@ bool file_entry_t::is_valid() const
}

// Fixup a path to have current platform's directory separator.
void fixup_path_separator(pal::string_t& path)
void fixup_dir_separator(pal::string_t& path)
{
const pal::char_t bundle_dir_separator = '/';

Expand All @@ -38,13 +37,11 @@ file_entry_t file_entry_t::read(reader_t &reader)

if (!entry.is_valid())
{
trace::error(_X("Failure processing application bundle; possible file corruption."));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we remove this - the error description seems accurate still... and not having any feedback makes it much harder to diagnose issues.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trace:error() routines were no-ops, since the backing functions were not ported. Therefore, I removed the calls from the prototype, because the failure can be easily identified in the debugger (which we needed anyway, since there was no trace output).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK - for prototype this is fine.

trace::error(_X("Invalid FileEntry detected."));
throw StatusCode::BundleExtractionFailure;
}

reader.read_path_string(entry.m_relative_path);
fixup_path_separator(entry.m_relative_path);
fixup_dir_separator(entry.m_relative_path);

return entry;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include "header.h"
#include "reader.h"
#include "error_codes.h"
#include "trace.h"

using namespace bundle;

Expand All @@ -22,9 +21,6 @@ header_t header_t::read(reader_t& reader)

if (!fixed_header->is_valid())
{
trace::error(_X("Failure processing application bundle."));
trace::error(_X("Bundle header version compatibility check failed."));

throw StatusCode::BundleExtractionFailure;
}

Expand Down
68 changes: 68 additions & 0 deletions src/coreclr/hosts/bundle/pal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// 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.

#ifndef PAL_H
#define PAL_H

#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
#include <cstring>
#include <cstdarg>
#include <cstdint>
#include <cassert>

#if defined(_WIN32)
#include <windows.h>
#else // defined(_WIN32)
#include <cstdlib>
#include <unistd.h>
#include <libgen.h>
#include <mutex>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#endif // defined(_WIN32)

#if defined(_WIN32)
#define DIR_SEPARATOR '\\'
#define PATH_MAX MAX_PATH

#else // defined(_WIN32)
#define DIR_SEPARATOR '/'

#if !defined(PATH_MAX)
#define PATH_MAX 4096
#endif
#endif // defined(_WIN32)

namespace pal
{
typedef std::basic_ifstream<char> ifstream_t;
typedef std::istreambuf_iterator<ifstream_t::char_type> istreambuf_iterator_t;
typedef std::basic_istream<char> istream_t;

typedef char char_t;
typedef std::string string_t;
typedef std::stringstream stringstream_t;

inline bool clr_palstring(const char* cstr, string_t& out) { out.assign(cstr); return true; }

#if defined(_WIN32)
typedef HMODULE dll_t;
typedef FARPROC proc_t;
inline int pathcmp(const char_t* path1, const char_t* path2) { return ::_stricmp(path1, path2); }
#else // defined(_WIN32)
typedef void* dll_t;
typedef void* proc_t;
inline int pathcmp(const char_t* path1, const char_t* path2) { return ::strcmp(path1, path2); }
#endif // defined(_WIN32)

void* map_file_readonly(const string_t& path, size_t& length);
bool unmap_file(void* addr, size_t length);
}

#endif // PAL_H
42 changes: 42 additions & 0 deletions src/coreclr/hosts/bundle/pal_unix.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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.

#include "pal.h"

#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>

void* pal::map_file_readonly(const pal::string_t& path, size_t& length)
{
int fd = open(path.c_str(), O_RDONLY, (S_IRUSR | S_IRGRP | S_IROTH));
if (fd == -1)
{
return nullptr;
}

struct stat buf;
if (fstat(fd, &buf) != 0)
{
close(fd);
return nullptr;
}

length = buf.st_size;
void* address = mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, 0);

if(address == nullptr)
{
close(fd);
return nullptr;
}

close(fd);
return address;
}

bool pal::unmap_file(void* addr, size_t length)
{
return munmap(addr, length) == 0;
}
46 changes: 46 additions & 0 deletions src/coreclr/hosts/bundle/pal_windows.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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.
#include "pal.h"

void* pal::map_file_readonly(const pal::string_t& path, size_t& length)
{
HANDLE file = CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (file == INVALID_HANDLE_VALUE)
{
return nullptr;
}

LARGE_INTEGER fileSize;
if (GetFileSizeEx(file, &fileSize) == 0)
{
CloseHandle(file);
return nullptr;
}
length = (size_t)fileSize.QuadPart;

HANDLE map = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);

if (map == NULL)
{
CloseHandle(file);
return nullptr;
}

void* address = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);

if (map == NULL)
{
CloseHandle(file);
return nullptr;
}

return address;
}

bool pal::unmap_file(void* addr, size_t length)
{
return UnmapViewOfFile(addr) != 0;
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

#include "reader.h"
#include "error_codes.h"
#include "trace.h"
#include <memory>

using namespace bundle;
Expand All @@ -17,8 +16,6 @@ const int8_t* reader_t::add_without_overflow(const int8_t* ptr, int64_t len)
// even if the actual arthmetic didn't overflow.
if (new_ptr < ptr)
{
trace::error(_X("Failure processing application bundle; possible file corruption."));
trace::error(_X("Arithmetic overflow computing bundle-bounds."));
throw StatusCode::BundleExtractionFailure;
}

Expand All @@ -29,8 +26,6 @@ void reader_t::set_offset(int64_t offset)
{
if (offset < 0 || offset >= m_bound)
{
trace::error(_X("Failure processing application bundle; possible file corruption."));
trace::error(_X("Arithmetic overflow while reading bundle."));
throw StatusCode::BundleExtractionFailure;
}

Expand All @@ -44,8 +39,6 @@ void reader_t::bounds_check(int64_t len)
// It is legal for post_read_ptr == m_bound_ptr after reading the last byte.
if (m_ptr < m_base_ptr || post_read_ptr > m_bound_ptr)
{
trace::error(_X("Failure processing application bundle; possible file corruption."));
trace::error(_X("Bounds check failed while reading the bundle."));
throw StatusCode::BundleExtractionFailure;
}
}
Expand All @@ -70,9 +63,6 @@ size_t reader_t::read_path_length()
if (second_byte & 0x80)
{
// There can be no more than two bytes in path_length
trace::error(_X("Failure processing application bundle; possible file corruption."));
trace::error(_X("Path length encoding read beyond two bytes."));

throw StatusCode::BundleExtractionFailure;
}

Expand All @@ -81,8 +71,6 @@ size_t reader_t::read_path_length()

if (length <= 0 || length > PATH_MAX)
{
trace::error(_X("Failure processing application bundle; possible file corruption."));
trace::error(_X("Path length is zero or too long."));
throw StatusCode::BundleExtractionFailure;
}

Expand All @@ -95,5 +83,5 @@ void reader_t::read_path_string(pal::string_t &str)
std::unique_ptr<uint8_t[]> buffer{ new uint8_t[size + 1] };
read(buffer.get(), size);
buffer[size] = 0; // null-terminator
pal::clr_palstring(reinterpret_cast<const char*>(buffer.get()), &str);
pal::clr_palstring(reinterpret_cast<const char*>(buffer.get()), str);
}