1 | //===-- FileSystem.cpp ----------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "lldb/Host/windows/windows.h" |
10 | |
11 | #include <share.h> |
12 | #include <shellapi.h> |
13 | #include <sys/stat.h> |
14 | #include <sys/types.h> |
15 | |
16 | #include "lldb/Host/FileSystem.h" |
17 | #include "lldb/Host/windows/AutoHandle.h" |
18 | #include "lldb/Host/windows/PosixApi.h" |
19 | |
20 | #include "llvm/Support/ConvertUTF.h" |
21 | #include "llvm/Support/FileSystem.h" |
22 | |
23 | using namespace lldb_private; |
24 | |
25 | const char *FileSystem::DEV_NULL = "nul" ; |
26 | |
27 | const char *FileSystem::PATH_CONVERSION_ERROR = |
28 | "Error converting path between UTF-8 and native encoding" ; |
29 | |
30 | Status FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) { |
31 | Status error; |
32 | std::wstring wsrc, wdst; |
33 | if (!llvm::ConvertUTF8toWide(Source: src.GetPath(), Result&: wsrc) || |
34 | !llvm::ConvertUTF8toWide(Source: dst.GetPath(), Result&: wdst)) |
35 | error.SetErrorString(PATH_CONVERSION_ERROR); |
36 | if (error.Fail()) |
37 | return error; |
38 | DWORD attrib = ::GetFileAttributesW(wdst.c_str()); |
39 | if (attrib == INVALID_FILE_ATTRIBUTES) { |
40 | error.SetError(::err: GetLastError(), type: lldb::eErrorTypeWin32); |
41 | return error; |
42 | } |
43 | bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY); |
44 | DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0; |
45 | BOOL result = ::CreateSymbolicLinkW(wsrc.c_str(), wdst.c_str(), flag); |
46 | if (!result) |
47 | error.SetError(::err: GetLastError(), type: lldb::eErrorTypeWin32); |
48 | return error; |
49 | } |
50 | |
51 | Status FileSystem::Readlink(const FileSpec &src, FileSpec &dst) { |
52 | Status error; |
53 | std::wstring wsrc; |
54 | if (!llvm::ConvertUTF8toWide(Source: src.GetPath(), Result&: wsrc)) { |
55 | error.SetErrorString(PATH_CONVERSION_ERROR); |
56 | return error; |
57 | } |
58 | |
59 | HANDLE h = ::CreateFileW(wsrc.c_str(), GENERIC_READ, |
60 | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, |
61 | OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL); |
62 | if (h == INVALID_HANDLE_VALUE) { |
63 | error.SetError(::err: GetLastError(), type: lldb::eErrorTypeWin32); |
64 | return error; |
65 | } |
66 | |
67 | std::vector<wchar_t> buf(PATH_MAX + 1); |
68 | // Subtract 1 from the path length since this function does not add a null |
69 | // terminator. |
70 | DWORD result = ::GetFinalPathNameByHandleW( |
71 | h, buf.data(), buf.size() - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); |
72 | std::string path; |
73 | if (result == 0) |
74 | error.SetError(::err: GetLastError(), type: lldb::eErrorTypeWin32); |
75 | else if (!llvm::convertWideToUTF8(Source: buf.data(), Result&: path)) |
76 | error.SetErrorString(PATH_CONVERSION_ERROR); |
77 | else |
78 | dst.SetFile(path, style: FileSpec::Style::native); |
79 | |
80 | ::CloseHandle(h); |
81 | return error; |
82 | } |
83 | |
84 | Status FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) { |
85 | return Status("ResolveSymbolicLink() isn't implemented on Windows" ); |
86 | } |
87 | |
88 | FILE *FileSystem::Fopen(const char *path, const char *mode) { |
89 | std::wstring wpath, wmode; |
90 | if (!llvm::ConvertUTF8toWide(Source: path, Result&: wpath)) |
91 | return nullptr; |
92 | if (!llvm::ConvertUTF8toWide(Source: mode, Result&: wmode)) |
93 | return nullptr; |
94 | FILE *file; |
95 | if (_wfopen_s(&file, wpath.c_str(), wmode.c_str()) != 0) |
96 | return nullptr; |
97 | return file; |
98 | } |
99 | |
100 | int FileSystem::Open(const char *path, int flags, int mode) { |
101 | std::wstring wpath; |
102 | if (!llvm::ConvertUTF8toWide(Source: path, Result&: wpath)) |
103 | return -1; |
104 | // All other bits are rejected by _wsopen_s |
105 | mode = mode & (_S_IREAD | _S_IWRITE); |
106 | int result; |
107 | ::_wsopen_s(&result, wpath.c_str(), flags, _SH_DENYNO, mode); |
108 | return result; |
109 | } |
110 | |