1 //===-- FileSystem.cpp ------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Host/windows/windows.h"
14 #include <sys/types.h>
16 #include "lldb/Host/FileSystem.h"
17 #include "lldb/Host/windows/AutoHandle.h"
19 #include "llvm/Support/ConvertUTF.h"
20 #include "llvm/Support/FileSystem.h"
22 using namespace lldb_private;
24 const char *FileSystem::DEV_NULL = "nul";
26 const char *FileSystem::PATH_CONVERSION_ERROR =
27 "Error converting path between UTF-8 and native encoding";
29 FileSpec::PathSyntax FileSystem::GetNativePathSyntax() {
30 return FileSpec::ePathSyntaxWindows;
33 Error FileSystem::MakeDirectory(const FileSpec &file_spec,
34 uint32_t file_permissions) {
35 // On Win32, the mode parameter is ignored, as Windows files and directories
37 // different permission model than POSIX.
40 llvm::sys::fs::create_directories(file_spec.GetPath(), true);
42 error.SetErrorString(err_code.message().c_str());
48 Error FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse) {
50 std::wstring path_buffer;
51 if (!llvm::ConvertUTF8toWide(file_spec.GetPath(), path_buffer)) {
52 error.SetErrorString(PATH_CONVERSION_ERROR);
56 BOOL result = ::RemoveDirectoryW(path_buffer.c_str());
58 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
60 // SHFileOperation() accepts a list of paths, and so must be
61 // double-null-terminated to
62 // indicate the end of the list. The first null terminator is there only in
64 // store but not the actual vector contents, and so we need to push twice.
65 path_buffer.push_back(0);
66 path_buffer.push_back(0);
68 SHFILEOPSTRUCTW shfos = {};
69 shfos.wFunc = FO_DELETE;
70 shfos.pFrom = (LPCWSTR)path_buffer.data();
71 shfos.fFlags = FOF_NO_UI;
73 int result = ::SHFileOperationW(&shfos);
74 // TODO(zturner): Correctly handle the intricacies of SHFileOperation return
77 error.SetErrorStringWithFormat("SHFileOperation failed");
82 Error FileSystem::GetFilePermissions(const FileSpec &file_spec,
83 uint32_t &file_permissions) {
85 // Beware that Windows's permission model is different from Unix's, and it's
86 // not clear if this API is supposed to check ACLs. To match the caller's
87 // expectations as closely as possible, we'll use Microsoft's _stat, which
88 // attempts to emulate POSIX stat. This should be good enough for basic
89 // checks like FileSpec::Readable.
90 struct _stat file_stats;
91 if (::_stat(file_spec.GetCString(), &file_stats) == 0) {
92 // The owner permission bits in "st_mode" currently match the definitions
93 // for the owner file mode bits.
94 file_permissions = file_stats.st_mode & (_S_IREAD | _S_IWRITE | _S_IEXEC);
96 error.SetErrorToErrno();
102 Error FileSystem::SetFilePermissions(const FileSpec &file_spec,
103 uint32_t file_permissions) {
105 error.SetErrorStringWithFormat("%s is not supported on this host",
106 LLVM_PRETTY_FUNCTION);
110 lldb::user_id_t FileSystem::GetFileSize(const FileSpec &file_spec) {
111 return file_spec.GetByteSize();
114 bool FileSystem::GetFileExists(const FileSpec &file_spec) {
115 return file_spec.Exists();
118 Error FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) {
120 std::wstring wsrc, wdst;
121 if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) ||
122 !llvm::ConvertUTF8toWide(dst.GetCString(), wdst))
123 error.SetErrorString(PATH_CONVERSION_ERROR);
124 else if (!::CreateHardLinkW(wsrc.c_str(), wdst.c_str(), nullptr))
125 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
129 int FileSystem::GetHardlinkCount(const FileSpec &file_spec) {
131 if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path))
135 ::CreateFileW(path.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
136 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
138 if (file_handle == INVALID_HANDLE_VALUE)
141 AutoHandle auto_file_handle(file_handle);
142 BY_HANDLE_FILE_INFORMATION file_info;
143 if (::GetFileInformationByHandle(file_handle, &file_info))
144 return file_info.nNumberOfLinks;
149 Error FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) {
151 std::wstring wsrc, wdst;
152 if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) ||
153 !llvm::ConvertUTF8toWide(dst.GetCString(), wdst))
154 error.SetErrorString(PATH_CONVERSION_ERROR);
157 DWORD attrib = ::GetFileAttributesW(wdst.c_str());
158 if (attrib == INVALID_FILE_ATTRIBUTES) {
159 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
162 bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY);
163 DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
164 BOOL result = ::CreateSymbolicLinkW(wsrc.c_str(), wdst.c_str(), flag);
166 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
170 Error FileSystem::Unlink(const FileSpec &file_spec) {
173 if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path)) {
174 error.SetErrorString(PATH_CONVERSION_ERROR);
177 BOOL result = ::DeleteFileW(path.c_str());
179 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
183 Error FileSystem::Readlink(const FileSpec &src, FileSpec &dst) {
186 if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc)) {
187 error.SetErrorString(PATH_CONVERSION_ERROR);
191 HANDLE h = ::CreateFileW(wsrc.c_str(), GENERIC_READ,
192 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
193 OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL);
194 if (h == INVALID_HANDLE_VALUE) {
195 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
199 std::vector<wchar_t> buf(PATH_MAX + 1);
200 // Subtract 1 from the path length since this function does not add a null
202 DWORD result = ::GetFinalPathNameByHandleW(
203 h, buf.data(), buf.size() - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
206 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
207 else if (!llvm::convertWideToUTF8(buf.data(), path))
208 error.SetErrorString(PATH_CONVERSION_ERROR);
210 dst.SetFile(path, false);
216 Error FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) {
217 return Error("ResolveSymbolicLink() isn't implemented on Windows");
220 bool FileSystem::IsLocal(const FileSpec &spec) {
222 // TODO: return true if the file is on a locally mounted file system
229 FILE *FileSystem::Fopen(const char *path, const char *mode) {
230 std::wstring wpath, wmode;
231 if (!llvm::ConvertUTF8toWide(path, wpath))
233 if (!llvm::ConvertUTF8toWide(mode, wmode))
236 if (_wfopen_s(&file, wpath.c_str(), wmode.c_str()) != 0)
241 int FileSystem::Stat(const char *path, struct stat *stats) {
243 if (!llvm::ConvertUTF8toWide(path, wpath)) {
248 #ifdef _USE_32BIT_TIME_T
249 struct _stat32 file_stats;
250 stat_result = ::_wstat32(wpath.c_str(), &file_stats);
252 struct _stat64i32 file_stats;
253 stat_result = ::_wstat64i32(wpath.c_str(), &file_stats);
255 if (stat_result == 0) {
256 static_assert(sizeof(struct stat) == sizeof(file_stats),
257 "stat and _stat32/_stat64i32 must have the same layout");
258 *stats = *reinterpret_cast<struct stat *>(&file_stats);