aboutsummaryrefslogtreecommitdiffstats
path: root/util/system/fs_win.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/fs_win.cpp
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/fs_win.cpp')
-rw-r--r--util/system/fs_win.cpp233
1 files changed, 233 insertions, 0 deletions
diff --git a/util/system/fs_win.cpp b/util/system/fs_win.cpp
new file mode 100644
index 0000000000..a410ccac06
--- /dev/null
+++ b/util/system/fs_win.cpp
@@ -0,0 +1,233 @@
+#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_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>
+
+ 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;
+ 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();
+ 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();
+ } else {
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ buf = TTempBuf(buf.Size() * 2);
+ } else {
+ ythrow yexception() << "can't read link " << name;
+ }
+ }
+ }
+ }
+
+ // 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;
+}
+*/
+
+}