Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

libs/filesystem/src/windows_tools.hpp

//  windows_tools.hpp  -----------------------------------------------------------------//

//  Copyright 2002-2009, 2014 Beman Dawes
//  Copyright 2001 Dietmar Kuehl

//  Distributed under the Boost Software License, Version 1.0.
//  See http://www.boost.org/LICENSE_1_0.txt

//  See library home page at http://www.boost.org/libs/filesystem

//--------------------------------------------------------------------------------------//

#ifndef BOOST_FILESYSTEM_SRC_WINDOWS_TOOLS_HPP_
#define BOOST_FILESYSTEM_SRC_WINDOWS_TOOLS_HPP_

#include <cstddef>
#include <boost/filesystem/config.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/file_status.hpp>
#include <boost/winapi/basic_types.hpp> // NTSTATUS_

#include <windows.h>

#include <boost/filesystem/detail/header.hpp> // must be the last #include

#ifndef IO_REPARSE_TAG_MOUNT_POINT
#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L)
#endif

#ifndef IO_REPARSE_TAG_SYMLINK
#define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
#endif

namespace boost {
namespace filesystem {
namespace detail {

BOOST_INLINE_VARIABLE BOOST_CONSTEXPR_OR_CONST wchar_t colon = L':';
BOOST_INLINE_VARIABLE BOOST_CONSTEXPR_OR_CONST wchar_t questionmark = L'?';

inline bool is_letter(wchar_t c)
{
    return (c >= L'A' && c <= L'Z') || (c >= L'a' && c <= L'z');
}

inline bool equal_extension(wchar_t const* p, wchar_t const (&x1)[5], wchar_t const (&x2)[5])
{
    return (p[0] == x1[0] || p[0] == x2[0]) &&
        (p[1] == x1[1] || p[1] == x2[1]) &&
        (p[2] == x1[2] || p[2] == x2[2]) &&
        (p[3] == x1[3] || p[3] == x2[3]) &&
        p[4] == 0;
}

inline boost::filesystem::perms make_permissions(boost::filesystem::path const& p, DWORD attr)
{
    boost::filesystem::perms prms = boost::filesystem::owner_read | boost::filesystem::group_read | boost::filesystem::others_read;
    if ((attr & FILE_ATTRIBUTE_READONLY) == 0u)
        prms |= boost::filesystem::owner_write | boost::filesystem::group_write | boost::filesystem::others_write;
    boost::filesystem::path ext = p.extension();
    wchar_t const* q = ext.c_str();
    if (equal_extension(q, L".exe", L".EXE") || equal_extension(q, L".com", L".COM") || equal_extension(q, L".bat", L".BAT") || equal_extension(q, L".cmd", L".CMD"))
        prms |= boost::filesystem::owner_exe | boost::filesystem::group_exe | boost::filesystem::others_exe;
    return prms;
}

bool is_reparse_point_a_symlink_ioctl(HANDLE h);

inline bool is_reparse_point_tag_a_symlink(ULONG reparse_point_tag)
{
    return reparse_point_tag == IO_REPARSE_TAG_SYMLINK
        // Issue 9016 asked that NTFS directory junctions be recognized as directories.
        // That is equivalent to recognizing them as symlinks, and then the normal symlink
        // mechanism will take care of recognizing them as directories.
        //
        // Directory junctions are very similar to symlinks, but have some performance
        // and other advantages over symlinks. They can be created from the command line
        // with "mklink /J junction-name target-path".
        //
        // Note that mounted filesystems also have the same repartse point tag, which makes
        // them look like directory symlinks in terms of Boost.Filesystem. read_symlink()
        // may return a volume path or NT path for such symlinks.
        || reparse_point_tag == IO_REPARSE_TAG_MOUNT_POINT; // aka "directory junction" or "junction"
}

#if !defined(UNDER_CE)

//! Platform-specific parameters for directory iterator construction
struct directory_iterator_params
{
    //! Handle of the directory to iterate over. If not \c INVALID_HANDLE_VALUE, the directory path is ignored.
    HANDLE use_handle;
    /*!
     * If \c use_handle is not \c INVALID_HANDLE_VALUE, specifies whether the directory iterator should close the handle upon destruction.
     * If \c false, the handle must remain valid for the lifetime of the iterator.
     */
    bool close_handle;
};

//! IO_STATUS_BLOCK definition from Windows SDK.
struct io_status_block
{
    union
    {
        boost::winapi::NTSTATUS_ Status;
        PVOID Pointer;
    };
    ULONG_PTR Information;
};

//! UNICODE_STRING definition from Windows SDK
struct unicode_string
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR Buffer;
};

//! OBJECT_ATTRIBUTES definition from Windows SDK
struct object_attributes
{
    ULONG Length;
    HANDLE RootDirectory;
    unicode_string* ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;
    PVOID SecurityQualityOfService;
};

#ifndef OBJ_CASE_INSENSITIVE
#define OBJ_CASE_INSENSITIVE 0x00000040
#endif
#ifndef OBJ_DONT_REPARSE
#define OBJ_DONT_REPARSE 0x00001000
#endif

#ifndef FILE_SUPERSEDE
#define FILE_SUPERSEDE 0x00000000
#endif
#ifndef FILE_OPEN
#define FILE_OPEN 0x00000001
#endif
#ifndef FILE_CREATE
#define FILE_CREATE 0x00000002
#endif
#ifndef FILE_OPEN_IF
#define FILE_OPEN_IF 0x00000003
#endif
#ifndef FILE_OVERWRITE
#define FILE_OVERWRITE 0x00000004
#endif
#ifndef FILE_OVERWRITE_IF
#define FILE_OVERWRITE_IF 0x00000005
#endif

#ifndef FILE_DIRECTORY_FILE
#define FILE_DIRECTORY_FILE 0x00000001
#endif
#ifndef FILE_OPEN_FOR_BACKUP_INTENT
#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
#endif
#ifndef FILE_OPEN_REPARSE_POINT
#define FILE_OPEN_REPARSE_POINT 0x00200000
#endif

//! NtCreateFile signature. Available since Windows 2000 (probably).
typedef boost::winapi::NTSTATUS_ (NTAPI NtCreateFile_t)(
    /*out*/ PHANDLE FileHandle,
    /*in*/ ACCESS_MASK DesiredAccess,
    /*in*/ object_attributes* ObjectAttributes,
    /*out*/ io_status_block* IoStatusBlock,
    /*in, optional*/ PLARGE_INTEGER AllocationSize,
    /*in*/ ULONG FileAttributes,
    /*in*/ ULONG ShareAccess,
    /*in*/ ULONG CreateDisposition,
    /*in*/ ULONG CreateOptions,
    /*in, optional*/ PVOID EaBuffer,
    /*in*/ ULONG EaLength);

extern NtCreateFile_t* nt_create_file_api;

//! PIO_APC_ROUTINE definition from Windows SDK
typedef VOID (NTAPI* pio_apc_routine) (PVOID ApcContext, io_status_block* IoStatusBlock, ULONG Reserved);

//! FILE_INFORMATION_CLASS enum entries
enum file_information_class
{
    file_directory_information_class = 1
};

//! NtQueryDirectoryFile signature. Available since Windows NT 4.0 (probably).
typedef boost::winapi::NTSTATUS_ (NTAPI NtQueryDirectoryFile_t)(
    /*in*/ HANDLE FileHandle,
    /*in, optional*/ HANDLE Event,
    /*in, optional*/ pio_apc_routine ApcRoutine,
    /*in, optional*/ PVOID ApcContext,
    /*out*/ io_status_block* IoStatusBlock,
    /*out*/ PVOID FileInformation,
    /*in*/ ULONG Length,
    /*in*/ file_information_class FileInformationClass,
    /*in*/ BOOLEAN ReturnSingleEntry,
    /*in, optional*/ unicode_string* FileName,
    /*in*/ BOOLEAN RestartScan);

extern NtQueryDirectoryFile_t* nt_query_directory_file_api;

#endif // !defined(UNDER_CE)

//! FILE_INFO_BY_HANDLE_CLASS enum entries
enum file_info_by_handle_class
{
    file_basic_info_class = 0,
    file_disposition_info_class = 4,
    file_attribute_tag_info_class = 9,
    file_id_both_directory_info_class = 10,
    file_id_both_directory_restart_info_class = 11,
    file_full_directory_info_class = 14,
    file_full_directory_restart_info_class = 15,
    file_id_extd_directory_info_class = 19,
    file_id_extd_directory_restart_info_class = 20,
    file_disposition_info_ex_class = 21
};

//! FILE_ATTRIBUTE_TAG_INFO definition from Windows SDK
struct file_attribute_tag_info
{
    DWORD FileAttributes;
    DWORD ReparseTag;
};

//! GetFileInformationByHandleEx signature. Available since Windows Vista.
typedef BOOL (WINAPI GetFileInformationByHandleEx_t)(
    /*__in*/  HANDLE hFile,
    /*__in*/  file_info_by_handle_class FileInformationClass, // the actual type is FILE_INFO_BY_HANDLE_CLASS enum
    /*__out_bcount(dwBufferSize)*/ LPVOID lpFileInformation,
    /*__in*/  DWORD dwBufferSize);

extern GetFileInformationByHandleEx_t* get_file_information_by_handle_ex_api;

//! HANDLE wrapper that automatically closes the handle
struct handle_wrapper
{
    HANDLE handle;

    handle_wrapper() BOOST_NOEXCEPT : handle(INVALID_HANDLE_VALUE) {}
    explicit handle_wrapper(HANDLE h) BOOST_NOEXCEPT : handle(h) {}
    ~handle_wrapper() BOOST_NOEXCEPT
    {
        if (handle != INVALID_HANDLE_VALUE)
            ::CloseHandle(handle);
    }
    BOOST_DELETED_FUNCTION(handle_wrapper(handle_wrapper const&))
    BOOST_DELETED_FUNCTION(handle_wrapper& operator=(handle_wrapper const&))
};

//! Creates a file handle
inline HANDLE create_file_handle(boost::filesystem::path const& p, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile = NULL)
{
    return ::CreateFileW(p.c_str(), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}

#if !defined(UNDER_CE)
//! Creates a file handle for a file relative to a previously opened base directory. The file path must be relative and in preferred format.
boost::winapi::NTSTATUS_ nt_create_file_handle_at(HANDLE& out, HANDLE basedir_handle, boost::filesystem::path const& p, ULONG FileAttributes, ACCESS_MASK DesiredAccess, ULONG ShareMode, ULONG CreateDisposition, ULONG CreateOptions);
#endif // !defined(UNDER_CE)

} // namespace detail
} // namespace filesystem
} // namespace boost

#include <boost/filesystem/detail/footer.hpp>

#endif // BOOST_FILESYSTEM_SRC_WINDOWS_TOOLS_HPP_