// xfilesystem_abi.h internal header
// Copyright (c) Microsoft Corporation. All rights reserved.
#pragma once
#ifndef _XFILESYSTEM_ABI_H
#define _XFILESYSTEM_ABI_H
#ifndef RC_INVOKED

#include <stdint.h>
#include <type_traits>

#pragma pack(push,_CRT_PACKING)
#pragma warning(push,_STL_WARNING_LEVEL)
#pragma warning(disable: _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_INLINE_VAR constexpr size_t __std_fs_max_path = 260; // #define MAX_PATH          260
_INLINE_VAR constexpr size_t __std_fs_temp_path_max = __std_fs_max_path + 1;
_INLINE_VAR constexpr long long __std_fs_file_time_epoch_adjustment = 0x19DB1DED53E8000LL; // TRANSITION, ABI

enum class __std_win_error : unsigned long
	{	// #defines are copied unmodified from winerror.h, hence spaces in the comments.
	_Success = 0,						// #define ERROR_SUCCESS                    0L
	_File_not_found = 2,				// #define ERROR_FILE_NOT_FOUND             2L
	_Path_not_found = 3,				// #define ERROR_PATH_NOT_FOUND             3L
	_Access_denied = 5,					// #define ERROR_ACCESS_DENIED              5L
	_Not_enough_memory = 8,				// #define ERROR_NOT_ENOUGH_MEMORY          8L
	_No_more_files = 18,				// #define ERROR_NO_MORE_FILES              18L
	_Sharing_violation = 32,			// #define ERROR_SHARING_VIOLATION          32L
	_Not_supported = 50,				// #define ERROR_NOT_SUPPORTED              50L
	_File_exists = 80,					// #define ERROR_FILE_EXISTS                80L
	_Invalid_parameter = 87,			// #define ERROR_INVALID_PARAMETER          87L
	_Directory_not_empty = 145,			// #define ERROR_DIR_NOT_EMPTY              145L
	_Already_exists = 183,				// #define ERROR_ALREADY_EXISTS             183L
	_Directory_name_is_invalid = 267,	// #define ERROR_DIRECTORY                  267L
	_Max = ~0UL							// sentinel not used by Win32
	};

enum class __std_fs_dir_handle : intptr_t { _Invalid = -1 };

enum class __std_fs_file_attr : unsigned long
	{
	_Readonly				= 0x00000001, // #define FILE_ATTRIBUTE_READONLY             0x00000001
	_Hidden					= 0x00000002, // #define FILE_ATTRIBUTE_HIDDEN               0x00000002
	_System					= 0x00000004, // #define FILE_ATTRIBUTE_SYSTEM               0x00000004
	_Directory				= 0x00000010, // #define FILE_ATTRIBUTE_DIRECTORY            0x00000010
	_Archive				= 0x00000020, // #define FILE_ATTRIBUTE_ARCHIVE              0x00000020
	_Device					= 0x00000040, // #define FILE_ATTRIBUTE_DEVICE               0x00000040
	_Normal					= 0x00000080, // #define FILE_ATTRIBUTE_NORMAL               0x00000080
	_Temporary				= 0x00000100, // #define FILE_ATTRIBUTE_TEMPORARY            0x00000100
	_Sparse_file			= 0x00000200, // #define FILE_ATTRIBUTE_SPARSE_FILE          0x00000200
	_Reparse_point			= 0x00000400, // #define FILE_ATTRIBUTE_REPARSE_POINT        0x00000400

	_Invalid				= 0xFFFFFFFF, // #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
	};
_BITMASK_OPS(__std_fs_file_attr)

enum class __std_fs_reparse_tag : unsigned long
	{
	_None			= 0,
	_Mount_point	= (0xA0000003L), // #define IO_REPARSE_TAG_MOUNT_POINT              (0xA0000003L)
	_Symlink		= (0xA000000CL), // #define IO_REPARSE_TAG_SYMLINK                  (0xA000000CL)
	};

struct __std_fs_filetime
	{						// typedef struct _FILETIME {
	unsigned long _Low;		//     DWORD dwLowDateTime;
	unsigned long _High;	//     DWORD dwHighDateTime;
	};						// } FILETIME, *PFILETIME, *LPFILETIME;

struct __std_fs_find_data
	{											// typedef struct _WIN32_FIND_DATAW {
	__std_fs_file_attr _Attributes;				//     DWORD dwFileAttributes;
	__std_fs_filetime _Creation_time;			//     FILETIME ftCreationTime;
	__std_fs_filetime _Last_access_time;		//     FILETIME ftLastAccessTime;
	__std_fs_filetime _Last_write_time;			//     FILETIME ftLastWriteTime;
	unsigned long _File_size_high;				//     DWORD nFileSizeHigh;
	unsigned long _File_size_low;				//     DWORD nFileSizeLow;

												// MSDN: dwReserved0 specifies the reparse point tag if
												// MSDN:  (dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0

	__std_fs_reparse_tag _Reparse_point_tag;	//     DWORD dwReserved0;
	unsigned long _Reserved1;					//     DWORD dwReserved1;
	wchar_t _File_name[__std_fs_max_path];		//     _Field_z_ WCHAR  cFileName[ MAX_PATH ];
	wchar_t _Short_file_name[14];				//     _Field_z_ WCHAR  cAlternateFileName[ 14 ];
	};											// } WIN32_FIND_DATAW, ... ;

enum class __std_fs_stats_flags : unsigned long
	{
	_None				= 0,

	_Follow_symlinks	= 0x01,	// resolve symlink
	_Attributes			= 0x02,	// read/has attributes
	_Reparse_tag		= 0x04,	// read/has reparse_tag; may not be combined with _Follow_symlinks
	_File_size			= 0x08,	// read/has file size
	_Link_count			= 0x10,	// read/has link count
	_Last_write_time	= 0x20,	// read/has last write time

	_All_data = _Attributes | _Reparse_tag | _File_size | _Link_count | _Last_write_time
	};

_BITMASK_OPS(__std_fs_stats_flags)

struct __std_fs_stats
	{
	long long _Last_write_time;
	unsigned long long _File_size;
	__std_fs_file_attr _Attributes;
	__std_fs_reparse_tag _Reparse_point_tag;
	unsigned long _Link_count;
	__std_fs_stats_flags _Available; // which fields are available
	};

struct __std_fs_reparse_data_buffer
	{	// typedef struct _REPARSE_DATA_BUFFER
	unsigned long _Reparse_tag;
	unsigned short _Reparse_data_length;
	unsigned short _Reserved;
	union
		{
		struct
			{
			unsigned short _Substitute_name_offset;
			unsigned short _Substitute_name_length;
			unsigned short _Print_name_offset;
			unsigned short _Print_name_length;
			unsigned long _Flags;
			wchar_t _Path_buffer[1];
			} _Symbolic_link_reparse_buffer;
		struct
			{
			unsigned short _Substitute_name_offset;
			unsigned short _Substitute_name_length;
			unsigned short _Print_name_offset;
			unsigned short _Print_name_length;
			wchar_t _Path_buffer[1];
			} _Mount_point_reparse_buffer;
		struct
			{
			unsigned char _Data_buffer[1];
			} _Generic_reparse_buffer;
		};
	};

struct __std_ulong_and_error
	{
	unsigned long _Size;
	__std_win_error _Error;
	};

enum class __std_fs_volume_name_kind : unsigned long
	{
	_Dos = 0,	// #define VOLUME_NAME_DOS  0x0
	_Guid = 1,	// #define VOLUME_NAME_GUID 0x1
	_Nt = 2,	// #define VOLUME_NAME_NT   0x2
	_None = 4	// #define VOLUME_NAME_NONE 0x4
	};

enum class __std_access_rights : unsigned long
	{
	_Delete = 0x00010000,	// #define DELETE                           (0x00010000L)
	_File_read_attributes = 0x0080,		// #define FILE_READ_ATTRIBUTES      ( 0x0080 )
	_File_write_attributes = 0x0100,	// #define FILE_WRITE_ATTRIBUTES     ( 0x0100 )
	};

_BITMASK_OPS(__std_access_rights);

enum class __std_fs_file_flags : unsigned long
	{
	_None = 0,
	_Backup_semantics = 0x02000000,		// #define FILE_FLAG_BACKUP_SEMANTICS      0x02000000
	_Open_reparse_point = 0x00200000,	// #define FILE_FLAG_OPEN_REPARSE_POINT    0x00200000
	};

_BITMASK_OPS(__std_fs_file_flags);

enum class __std_fs_file_handle : intptr_t { _Invalid = -1 };

enum class __std_code_page : unsigned int
	{
	_Utf8 = 65001
	};

struct __std_fs_convert_result
	{
	int _Len;
	__std_win_error _Err;
	};

struct __std_fs_file_id
	{											// typedef struct _FILE_ID_INFO {
	unsigned long long _Volume_serial_number;	//    ULONGLONG VolumeSerialNumber;
	unsigned char _Id[16];						//    FILE_ID_128 FileId;
	};											// } FILE_ID_INFO, ...;

enum class __std_fs_copy_options
	{
	_None = 0x0,

	_Existing_mask = 0xF,
	_Skip_existing = 0x1,
	_Overwrite_existing = 0x2,
	_Update_existing = 0x4,
	};

_BITMASK_OPS(__std_fs_copy_options);

_EXTERN_C
_NODISCARD __std_ulong_and_error __stdcall __std_fs_get_full_path_name(
	_In_z_                       const wchar_t * _Source,
	_In_                         unsigned long   _Target_size,
	_Out_writes_z_(_Target_size) wchar_t *       _Target
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_open_handle(
	_Out_  __std_fs_file_handle * _Handle,
	_In_z_ const wchar_t *        _File_name,
	_In_   __std_access_rights    _Desired_access,
	_In_   __std_fs_file_flags    _Flags
	) _NOEXCEPT;

void __stdcall __std_fs_close_handle(__std_fs_file_handle _Handle) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_get_file_attributes_by_handle(
	_In_  __std_fs_file_handle _Handle,
	_Out_ unsigned long *      _File_attributes
	) _NOEXCEPT;

_NODISCARD __std_ulong_and_error __stdcall __std_fs_get_final_path_name_by_handle(
	_In_                         __std_fs_file_handle      _Handle,
	_Out_writes_z_(_Target_size) wchar_t *                 _Target,
	_In_                         unsigned long             _Target_size,
	_In_                         __std_fs_volume_name_kind _Flags
	) _NOEXCEPT;

struct __std_fs_copy_file_result
	{
	bool _Copied;
	__std_win_error _Error;
	};

_NODISCARD __std_fs_copy_file_result __stdcall __std_fs_copy_file(
	_In_z_ const wchar_t *       _Source,
	_In_z_ const wchar_t *       _Target,
	_In_   __std_fs_copy_options _Options
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_directory_iterator_open(
	_In_z_  const wchar_t *       _Path_spec,
	_Inout_ __std_fs_dir_handle * _Handle,
	_Out_   __std_fs_find_data *  _Results) _NOEXCEPT;

void __stdcall __std_fs_directory_iterator_close(_In_ __std_fs_dir_handle _Handle) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_get_stats(
	_In_z_ const wchar_t *      _Path,
	_Out_  __std_fs_stats *     _Stats,
	_In_   __std_fs_stats_flags _Flags,
	_In_   __std_fs_file_attr   _Symlink_attribute_hint = __std_fs_file_attr::_Invalid
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_directory_iterator_advance(
	_In_ __std_fs_dir_handle _Handle,
	_Out_ __std_fs_find_data * _Results) _NOEXCEPT;

_NODISCARD __std_code_page __stdcall __std_fs_code_page() _NOEXCEPT;

_NODISCARD __std_fs_convert_result __stdcall __std_fs_convert_narrow_to_wide(
	_In_                          __std_code_page _Code_page,
	_In_reads_(_Input_len)        const char * _Input_str,
	_In_                          int _Input_len,
	_Out_writes_opt_(_Output_len) wchar_t * _Output_str,
	_In_                          int _Output_len
	) _NOEXCEPT;

_NODISCARD __std_fs_convert_result __stdcall __std_fs_convert_wide_to_narrow(
	_In_                          __std_code_page _Code_page,
	_In_reads_(_Input_len)        const wchar_t * _Input_str,
	_In_                          int _Input_len,
	_Out_writes_opt_(_Output_len) char * _Output_str,
	_In_                          int _Output_len
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_get_file_id(
	_Out_  __std_fs_file_id * _Id,
	_In_z_ const wchar_t *    _Path
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_set_last_write_time(
	_In_   long long       _Last_write_filetime,
	_In_z_ const wchar_t * _Path
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_change_permissions(
	_In_z_ const wchar_t * _Path,
	_In_   bool            _Follow_symlinks,
	_In_   bool            _Readonly
	) _NOEXCEPT;

_NODISCARD __std_ulong_and_error __stdcall __std_fs_get_temp_path(
	_Out_writes_z_(__std_fs_temp_path_max) wchar_t * _Target
	) _NOEXCEPT;

_NODISCARD __std_ulong_and_error __stdcall __std_fs_get_current_path(
	_In_                         unsigned long   _Target_size,
	_Out_writes_z_(_Target_size) wchar_t *       _Target
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_set_current_path(
	_In_z_ const wchar_t * _Target
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_create_directory_symbolic_link(
	_In_z_ const wchar_t * _Symlink_file_name,
	_In_z_ const wchar_t * _Target_file_name
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_create_hard_link(
	_In_z_ const wchar_t * _File_name,
	_In_z_ const wchar_t * _Existing_file_name
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_create_symbolic_link(
	_In_z_ const wchar_t * _Symlink_file_name,
	_In_z_ const wchar_t * _Target_file_name
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_read_reparse_data_buffer(
	_In_                             __std_fs_file_handle _Handle,
	_Out_writes_bytes_(_Buffer_size) void *               _Buffer,
	_In_                             unsigned long        _Buffer_size
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_read_name_from_reparse_data_buffer(
	_In_  __std_fs_reparse_data_buffer * _Handle,
	_Out_ wchar_t **                     _Offset,
	_Out_ unsigned short *               _Length
	) _NOEXCEPT;

struct __std_fs_create_directory_result
	{
	bool _Created;
	__std_win_error _Error;
	};

_NODISCARD __std_fs_create_directory_result __stdcall __std_fs_create_directory(
	_In_z_ const wchar_t * _New_directory
	) _NOEXCEPT;

_NODISCARD __std_fs_create_directory_result __stdcall __std_fs_create_directory_template(
	_In_z_ const wchar_t * _Template_directory,
	_In_z_ const wchar_t * _New_directory
	) _NOEXCEPT;

struct __std_fs_remove_result
	{
	bool _Removed;
	__std_win_error _Error;
	};

_NODISCARD __std_fs_remove_result __stdcall __std_fs_remove(
	_In_z_ const wchar_t * _Target
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_rename(
	_In_z_ const wchar_t * _Source,
	_In_z_ const wchar_t * _Target
	) _NOEXCEPT;

_NODISCARD __std_win_error __stdcall __std_fs_space(
	_In_z_ const wchar_t * _Target,
	_Out_  uintmax_t *     _Available,
	_Out_  uintmax_t *     _Total_bytes,
	_Out_  uintmax_t *     _Free_bytes
	) _NOEXCEPT;
_END_EXTERN_C

_STD_BEGIN
struct _Fs_file
	{
	__std_fs_file_handle _Raw;

	explicit _Fs_file(void * const _Handle)
		: _Raw{reinterpret_cast<intptr_t>(_Handle)}
		{
		}

	_Fs_file(const wchar_t * const _File_name, const __std_access_rights _Desired_access,
		const __std_fs_file_flags _Flags, __std_win_error * const _Err)
		{
		*_Err = __std_fs_open_handle(&_Raw, _File_name, _Desired_access, _Flags);
		}

	_Fs_file(const _Fs_file&) = delete;
	_Fs_file& operator=(const _Fs_file&) = delete;

	~_Fs_file()
		{
		__std_fs_close_handle(_Raw);
		}

	_NODISCARD void * _Get() const
		{
		return (reinterpret_cast<void *>(_Raw));
		}
	};

	// FUNCTION OBJECT _Is_slash
struct _Is_slash_oper
	{	// predicate testing if input is a preferred-separator or fallback-separator
	_NODISCARD constexpr bool operator()(const wchar_t _Ch) const
		{	// test if _Ch is a preferred-separator or fallback-separator
		return (_Ch == L'\\' || _Ch == L'/');
		}
	};

_INLINE_VAR constexpr _Is_slash_oper _Is_slash{};
_STD_END

#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)

#endif /* RC_INVOKED */
#endif /* _XFILESYSTEM_ABI_H */
