You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by an...@apache.org on 2017/11/30 03:28:21 UTC
[02/13] mesos git commit: Windows: Fixed `fs::symlink` to not need
admin privileges.
Windows: Fixed `fs::symlink` to not need admin privileges.
This new feature of Windows 10 allows us to make symlinks without being
an administrator. In the future, we may want to do a version check, as
this is likely to fail on versions of Windows which don't support this
flag. Resolves MESOS-7370.
Review: https://reviews.apache.org/r/63809
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/e1d7c6dd
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/e1d7c6dd
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/e1d7c6dd
Branch: refs/heads/master
Commit: e1d7c6dddd1701579a10e0f408b06adfb75e4a93
Parents: 24550e7
Author: Andrew Schwartzmeyer <an...@schwartzmeyer.com>
Authored: Thu Oct 26 11:22:17 2017 -0700
Committer: Andrew Schwartzmeyer <an...@schwartzmeyer.com>
Committed: Wed Nov 29 19:24:10 2017 -0800
----------------------------------------------------------------------
.../stout/internal/windows/reparsepoint.hpp | 145 +++++++------------
1 file changed, 56 insertions(+), 89 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/e1d7c6dd/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp b/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp
index e3d0448..0ff5d68 100644
--- a/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp
+++ b/3rdparty/stout/include/stout/internal/windows/reparsepoint.hpp
@@ -13,11 +13,9 @@
#ifndef __STOUT_INTERNAL_WINDOWS_REPARSEPOINT_HPP__
#define __STOUT_INTERNAL_WINDOWS_REPARSEPOINT_HPP__
-#include <mutex>
#include <string>
#include <stout/nothing.hpp>
-#include <stout/synchronized.hpp>
#include <stout/try.hpp>
#include <stout/windows.hpp>
@@ -45,6 +43,9 @@ enum class FollowSymlink
} // namespace os {
+namespace internal {
+namespace windows {
+
// We pass this struct to `DeviceIoControl` to get information about a reparse
// point (including things like whether it's a symlink). It is normally part of
// the Device Driver Kit (DDK), specifically `nitfs.h`, but rather than taking
@@ -55,69 +56,44 @@ enum class FollowSymlink
// [1] http://www.boost.org/doc/libs/1_46_1/libs/filesystem/v3/src/operations.cpp
// [2] https://msdn.microsoft.com/en-us/library/cc232007.aspx
// [3] https://msdn.microsoft.com/en-us/library/cc232005.aspx
-//
-// We are declaring this structure (and the REPARSE_DATA_BUFFER_HEADER_SIZE
-// macro right below it in the global namespace, to be consistent with the
-// original Windows DDK declarations.
typedef struct _REPARSE_DATA_BUFFER
{
// Describes, among other things, which type of reparse point this is (e.g.,
// a symlink).
- ULONG ReparseTag;
+ ULONG ReparseTag;
// Size in bytes of common portion of the `REPARSE_DATA_BUFFER`.
- USHORT ReparseDataLength;
+ USHORT ReparseDataLength;
// Unused. Ignore.
- USHORT Reserved;
- union
+ USHORT Reserved;
+ // Holds symlink data.
+ struct
{
- // Holds symlink data.
- struct
- {
- // Byte offset in `PathBuffer` where the substitute name begins.
- // Calculated as an offset from 0.
- USHORT SubstituteNameOffset;
- // Length in bytes of the substitute name.
- USHORT SubstituteNameLength;
- // Byte offset in `PathBuffer` where the print name begins. Calculated as
- // an offset from 0.
- USHORT PrintNameOffset;
- // Length in bytes of the print name.
- USHORT PrintNameLength;
- // Indicates whether symlink is absolute or relative. If flags containing
- // `SYMLINK_FLAG_RELATIVE`, then the substitute name is a relative
- // symlink.
- ULONG Flags;
- // The first byte of the path string -- according to the documentation[1],
- // this is followed in memory by the rest of the path string. The "path
- // string" itself is a unicode char array containing both substitute name
- // and print name. They can occur in any order. Use the offset and length
- // of each in this struct to calculate where each starts and ends.
- //
- // [1] https://msdn.microsoft.com/en-us/library/windows/hardware/ff552012(v=vs.85).aspx
- WCHAR PathBuffer[1];
- } SymbolicLinkReparseBuffer;
-
- // Unused: holds mount point data.
- struct
- {
- USHORT SubstituteNameOffset;
- USHORT SubstituteNameLength;
- USHORT PrintNameOffset;
- USHORT PrintNameLength;
- WCHAR PathBuffer[1];
- } MountPointReparseBuffer;
- struct
- {
- UCHAR DataBuffer[1];
- } GenericReparseBuffer;
- };
+ // Byte offset in `PathBuffer` where the substitute name begins.
+ // Calculated as an offset from 0.
+ USHORT SubstituteNameOffset;
+ // Length in bytes of the substitute name.
+ USHORT SubstituteNameLength;
+ // Byte offset in `PathBuffer` where the print name begins. Calculated as
+ // an offset from 0.
+ USHORT PrintNameOffset;
+ // Length in bytes of the print name.
+ USHORT PrintNameLength;
+ // Indicates whether symlink is absolute or relative. If flags containing
+ // `SYMLINK_FLAG_RELATIVE`, then the substitute name is a relative
+ // symlink.
+ ULONG Flags;
+ // The path string; the Windows declaration is the first byte, but we
+ // declare a suitably sized array so we can use this struct more easily. The
+ // "path string" itself is a Unicode `wchar` array containing both
+ // substitute name and print name. They can occur in any order. Use the
+ // offset and length of each in this struct to calculate where each starts
+ // and ends.
+ //
+ // https://msdn.microsoft.com/en-us/library/windows/hardware/ff552012(v=vs.85).aspx
+ WCHAR PathBuffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ } SymbolicLinkReparseBuffer;
} REPARSE_DATA_BUFFER;
-#define REPARSE_DATA_BUFFER_HEADER_SIZE \
- FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
-
-namespace internal {
-namespace windows {
// Convenience struct for holding symlink data, meant purely for internal use.
// We pass this around instead of the `REPARSE_DATA_BUFFER` struct, simply
@@ -254,11 +230,7 @@ inline Try<SymbolicLink> get_symbolic_link_data(const HANDLE handle)
// [1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa364571(v=vs.85).aspx
// [2] https://svn.boost.org/trac/boost/ticket/4663
// [3] https://msdn.microsoft.com/en-us/library/windows/desktop/aa363216(v=vs.85).aspx
- const size_t reparse_point_data_size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
- BYTE buffer[reparse_point_data_size];
- REPARSE_DATA_BUFFER* reparse_point_data =
- reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer);
-
+ REPARSE_DATA_BUFFER buffer;
DWORD ignored = 0;
// The semantics of this function are: get the reparse data associated with
@@ -269,8 +241,8 @@ inline Try<SymbolicLink> get_symbolic_link_data(const HANDLE handle)
FSCTL_GET_REPARSE_POINT, // Gets reparse point data for file/folder.
nullptr, // Ignored.
0, // Ignored.
- reparse_point_data,
- reparse_point_data_size,
+ &buffer,
+ sizeof(buffer),
&ignored, // Ignored.
nullptr); // Ignored.
@@ -280,18 +252,13 @@ inline Try<SymbolicLink> get_symbolic_link_data(const HANDLE handle)
"failed");
}
- return build_symbolic_link(*reparse_point_data);
+ return build_symbolic_link(buffer);
}
// Creates a reparse point with the specified target. The target can be either
// a file (in which case a junction is created), or a folder (in which case a
// mount point is created).
-//
-// Calling this function results in a temporary elevation of the process token's
-// privileges (if those privileges are not already held), to allow for junction
-// or mount point creation. This operation is gated by a static mutex, which
-// makes it thread-safe.
inline Try<Nothing> create_symbolic_link(
const std::string& target,
const std::string& reparse_point)
@@ -320,8 +287,8 @@ inline Try<Nothing> create_symbolic_link(
// Determine if target is a folder or a file. This makes a difference
// in the way we call `create_symbolic_link`.
- const Try<DWORD> attributes = ::internal::windows::get_file_attributes(
- ::internal::windows::longpath(absolute_target_path));
+ const Try<DWORD> attributes = get_file_attributes(
+ longpath(absolute_target_path));
if (attributes.isError()) {
return Error(attributes.error());
@@ -344,24 +311,24 @@ inline Try<Nothing> create_symbolic_link(
"Path '" + absolute_target_path + "' is already a reparse point");
}
- // `CreateSymbolicLink` adjusts the process token's privileges to allow for
- // symlink creation. MSDN[1] makes no guarantee when it comes to the thread
- // safety of this operation, so we are making use of a mutex to prevent
- // multiple concurrent calls.
- //
- // [1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa363866(v=vs.85).aspx
- static std::mutex adjust_privileges_mutex;
- synchronized(adjust_privileges_mutex) {
- if (!::CreateSymbolicLinkW(
- // Path to link.
- longpath(real_reparse_point_path.get()).data(),
- // Path to target.
- longpath(real_target_path.get()).data(),
- target_is_folder ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0)) {
- return WindowsError(
- "'internal::windows::create_symbolic_link': 'CreateSymbolicLink' "
- "call failed");
- }
+ // Avoid requiring administrative privileges to create symbolic links.
+ DWORD flags = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
+ if (target_is_folder) {
+ flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
+ }
+
+ // `CreateSymbolicLink` normally adjusts the process token's privileges to
+ // allow for symlink creation; however, we explicitly avoid this with the
+ // above flag.
+ if (!::CreateSymbolicLinkW(
+ // Path to link.
+ longpath(real_reparse_point_path.get()).data(),
+ // Path to target.
+ longpath(real_target_path.get()).data(),
+ flags)) {
+ return WindowsError(
+ "'internal::windows::create_symbolic_link': 'CreateSymbolicLink' "
+ "call failed");
}
return Nothing();