xref: /llvm-project/lldb/source/Host/windows/FileSystem.cpp (revision de687eac24a3f4bac8b5ff9975f51ab98775f2d5)
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(src.GetPath(), wsrc) ||
34       !llvm::ConvertUTF8toWide(dst.GetPath(), wdst))
35     error = Status::FromErrorString(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 = Status(::GetLastError(), 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 = Status(::GetLastError(), 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(src.GetPath(), wsrc)) {
55     error = Status::FromErrorString(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 = Status(::GetLastError(), 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 = Status(::GetLastError(), lldb::eErrorTypeWin32);
75   else if (!llvm::convertWideToUTF8(buf.data(), path))
76     error = Status::FromErrorString(PATH_CONVERSION_ERROR);
77   else
78     dst.SetFile(path, FileSpec::Style::native);
79 
80   ::CloseHandle(h);
81   return error;
82 }
83 
84 Status FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) {
85   return Status::FromErrorString(
86       "ResolveSymbolicLink() isn't implemented on Windows");
87 }
88 
89 FILE *FileSystem::Fopen(const char *path, const char *mode) {
90   std::wstring wpath, wmode;
91   if (!llvm::ConvertUTF8toWide(path, wpath))
92     return nullptr;
93   if (!llvm::ConvertUTF8toWide(mode, wmode))
94     return nullptr;
95   FILE *file;
96   if (_wfopen_s(&file, wpath.c_str(), wmode.c_str()) != 0)
97     return nullptr;
98   return file;
99 }
100 
101 int FileSystem::Open(const char *path, int flags, int mode) {
102   std::wstring wpath;
103   if (!llvm::ConvertUTF8toWide(path, wpath))
104     return -1;
105   // All other bits are rejected by _wsopen_s
106   mode = mode & (_S_IREAD | _S_IWRITE);
107   int result;
108   ::_wsopen_s(&result, wpath.c_str(), flags, _SH_DENYNO, mode);
109   return result;
110 }
111