diff options
author | alexv-smirnov <alex@ydb.tech> | 2022-12-20 00:50:48 +0300 |
---|---|---|
committer | alexv-smirnov <alex@ydb.tech> | 2022-12-20 00:50:48 +0300 |
commit | 84f2cfa253cc618438ed6e9d68b33fa7c0d88cb9 (patch) | |
tree | f0cf2236e0aafb3e437199f1ac7b559e7fad554a /util/system/fs_win.cpp | |
parent | bde6febc1ad3b826e72746de21d7250803e8e0b5 (diff) | |
download | ydb-84f2cfa253cc618438ed6e9d68b33fa7c0d88cb9.tar.gz |
add windows platform to ydb github export
Diffstat (limited to 'util/system/fs_win.cpp')
-rw-r--r-- | util/system/fs_win.cpp | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/util/system/fs_win.cpp b/util/system/fs_win.cpp new file mode 100644 index 0000000000..45d7454b2f --- /dev/null +++ b/util/system/fs_win.cpp @@ -0,0 +1,255 @@ +#include "fs_win.h" +#include "defaults.h" +#include "maxlen.h" + +#include <util/folder/dirut.h> +#include <util/charset/wide.h> +#include "file.h" + +#include <winioctl.h> + +namespace NFsPrivate { + static LPCWSTR UTF8ToWCHAR(const TStringBuf str, TUtf16String& wstr) { + wstr.resize(str.size()); + size_t written = 0; + if (!UTF8ToWide(str.data(), str.size(), wstr.begin(), written)) + return nullptr; + wstr.erase(written); + static_assert(sizeof(WCHAR) == sizeof(wchar16), "expect sizeof(WCHAR) == sizeof(wchar16)"); + return (const WCHAR*)wstr.data(); + } + + static TString WCHARToUTF8(const LPWSTR wstr, size_t len) { + static_assert(sizeof(WCHAR) == sizeof(wchar16), "expect sizeof(WCHAR) == sizeof(wchar16)"); + + return WideToUTF8((wchar16*)wstr, len); + } + + HANDLE CreateFileWithUtf8Name(const TStringBuf fName, ui32 accessMode, ui32 shareMode, ui32 createMode, ui32 attributes, bool inheritHandle) { + TUtf16String wstr; + LPCWSTR wname = UTF8ToWCHAR(fName, wstr); + if (!wname) { + ::SetLastError(ERROR_INVALID_NAME); + return INVALID_HANDLE_VALUE; + } + SECURITY_ATTRIBUTES secAttrs; + secAttrs.bInheritHandle = inheritHandle ? TRUE : FALSE; + secAttrs.lpSecurityDescriptor = nullptr; + secAttrs.nLength = sizeof(secAttrs); + return ::CreateFileW(wname, accessMode, shareMode, &secAttrs, createMode, attributes, nullptr); + } + + bool WinRename(const TString& oldPath, const TString& newPath) { + TUtf16String op, np; + LPCWSTR opPtr = UTF8ToWCHAR(oldPath, op); + LPCWSTR npPtr = UTF8ToWCHAR(newPath, np); + if (!opPtr || !npPtr) { + ::SetLastError(ERROR_INVALID_NAME); + return false; + } + + return MoveFileExW(opPtr, npPtr, MOVEFILE_REPLACE_EXISTING) != 0; + } + + bool WinRemove(const TString& path) { + TUtf16String wstr; + LPCWSTR wname = UTF8ToWCHAR(path, wstr); + if (!wname) { + ::SetLastError(ERROR_INVALID_NAME); + return false; + } + WIN32_FILE_ATTRIBUTE_DATA fad; + if (::GetFileAttributesExW(wname, GetFileExInfoStandard, &fad)) { + if (fad.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + fad.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; + ::SetFileAttributesW(wname, fad.dwFileAttributes); + } + if (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + return ::RemoveDirectoryW(wname) != 0; + return ::DeleteFileW(wname) != 0; + } + + return false; + } + + bool WinSymLink(const TString& targetName, const TString& linkName) { + TString tName(targetName); + { + size_t pos; + while ((pos = tName.find('/')) != TString::npos) + tName.replace(pos, 1, LOCSLASH_S); + } + TUtf16String tstr; + LPCWSTR wname = UTF8ToWCHAR(tName, tstr); + TUtf16String lstr; + LPCWSTR lname = UTF8ToWCHAR(linkName, lstr); + + // we can't create a dangling link to a dir in this way + ui32 attr = ::GetFileAttributesW(wname); + if (attr == INVALID_FILE_ATTRIBUTES) { + TTempBuf result; + if (GetFullPathNameW(lname, result.Size(), (LPWSTR)result.Data(), 0) != 0) { + TString fullPath = WideToUTF8(TWtringBuf((const wchar16*)result.Data())); + TStringBuf linkDir(fullPath); + linkDir.RNextTok('\\'); + + if (linkDir) { + TString fullTarget(tName); + resolvepath(fullTarget, TString{linkDir}); + TUtf16String fullTargetW; + LPCWSTR ptrFullTarget = UTF8ToWCHAR(fullTarget, fullTargetW); + attr = ::GetFileAttributesW(ptrFullTarget); + } + } + } + return 0 != CreateSymbolicLinkW(lname, wname, attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0); + } + + bool WinHardLink(const TString& existingPath, const TString& newPath) { + TUtf16String ep, np; + LPCWSTR epPtr = UTF8ToWCHAR(existingPath, ep); + LPCWSTR npPtr = UTF8ToWCHAR(newPath, np); + if (!epPtr || !npPtr) { + ::SetLastError(ERROR_INVALID_NAME); + return false; + } + + return (CreateHardLinkW(npPtr, epPtr, nullptr) != 0); + } + + bool WinExists(const TString& path) { + TUtf16String buf; + LPCWSTR ptr = UTF8ToWCHAR(path, buf); + return ::GetFileAttributesW(ptr) != INVALID_FILE_ATTRIBUTES; + } + + TString WinCurrentWorkingDirectory() { + TTempBuf result; + LPWSTR buf = reinterpret_cast<LPWSTR>(result.Data()); + int r = GetCurrentDirectoryW(result.Size() / sizeof(WCHAR), buf); + if (r == 0) + throw TIoSystemError() << "failed to GetCurrentDirectory"; + return WCHARToUTF8(buf, r); + } + + bool WinSetCurrentWorkingDirectory(const TString& path) { + TUtf16String wstr; + LPCWSTR wname = UTF8ToWCHAR(path, wstr); + if (!wname) { + ::SetLastError(ERROR_INVALID_NAME); + return false; + } + return SetCurrentDirectoryW(wname); + } + + bool WinMakeDirectory(const TString& path) { + TUtf16String buf; + LPCWSTR ptr = UTF8ToWCHAR(path, buf); + return CreateDirectoryW(ptr, (LPSECURITY_ATTRIBUTES) nullptr); + } + // edited part of <Ntifs.h> from Windows DDK + +#define SYMLINK_FLAG_RELATIVE 1 + + struct TReparseBufferHeader { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + }; + + struct TSymbolicLinkReparseBuffer: public TReparseBufferHeader { + ULONG Flags; // 0 or SYMLINK_FLAG_RELATIVE + wchar16 PathBuffer[1]; + }; + + struct TMountPointReparseBuffer: public TReparseBufferHeader { + wchar16 PathBuffer[1]; + }; + + struct TGenericReparseBuffer { + wchar16 DataBuffer[1]; + }; + + struct REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + TSymbolicLinkReparseBuffer SymbolicLinkReparseBuffer; + TMountPointReparseBuffer MountPointReparseBuffer; + TGenericReparseBuffer GenericReparseBuffer; + }; + }; + + // the end of edited part of <Ntifs.h> + + // For more info see: + // * https://docs.microsoft.com/en-us/windows/win32/fileio/reparse-points + // * https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/fsctl-get-reparse-point + // * https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_reparse_data_buffer + REPARSE_DATA_BUFFER* ReadReparsePoint(HANDLE h, TTempBuf& buf) { + while (true) { + DWORD bytesReturned = 0; + BOOL res = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, nullptr, 0, buf.Data(), buf.Size(), &bytesReturned, nullptr); + if (res) { + REPARSE_DATA_BUFFER* rdb = (REPARSE_DATA_BUFFER*)buf.Data(); + return rdb; + } else { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + buf = TTempBuf(buf.Size() * 2); + } else { + return nullptr; + } + } + } + } + + TString WinReadLink(const TString& name) { + TFileHandle h = CreateFileWithUtf8Name(name, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, true); + TTempBuf buf; + REPARSE_DATA_BUFFER* rdb = ReadReparsePoint(h, buf); + if (rdb == nullptr) { + ythrow TIoSystemError() << "can't read reparse point " << name; + } + if (rdb->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + wchar16* str = (wchar16*)&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar16)]; + size_t len = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar16); + return WideToUTF8(str, len); + } else if (rdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + wchar16* str = (wchar16*)&rdb->MountPointReparseBuffer.PathBuffer[rdb->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar16)]; + size_t len = rdb->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar16); + return WideToUTF8(str, len); + } + //this reparse point is unsupported in arcadia + return TString(); + } + + ULONG WinReadReparseTag(HANDLE h) { + TTempBuf buf; + REPARSE_DATA_BUFFER* rdb = ReadReparsePoint(h, buf); + return rdb ? rdb->ReparseTag : 0; + } + + // we can't use this function to get an analog of unix inode due to a lot of NTFS folders do not have this GUID + //(it will be 'create' case really) + /* +bool GetObjectId(const char* path, GUID* id) { + TFileHandle h = CreateFileWithUtf8Name(path, 0, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, true); + if (h.IsOpen()) { + FILE_OBJECTID_BUFFER fob; + DWORD resSize = 0; + if (DeviceIoControl(h, FSCTL_CREATE_OR_GET_OBJECT_ID, nullptr, 0, &fob, sizeof(fob), &resSize, nullptr)) { + Y_ASSERT(resSize == sizeof(fob)); + memcpy(id, &fob.ObjectId, sizeof(GUID)); + return true; + } + } + memset(id, 0, sizeof(GUID)); + return false; +} +*/ + +} |