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;
25 FileSystem::DEV_NULL = "nul";
27 const char *FileSystem::PATH_CONVERSION_ERROR = "Error converting path between UTF-8 and native encoding";
30 FileSystem::GetNativePathSyntax()
32 return FileSpec::ePathSyntaxWindows;
36 FileSystem::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions)
38 // On Win32, the mode parameter is ignored, as Windows files and directories support a
39 // different permission model than POSIX.
41 const auto err_code = llvm::sys::fs::create_directories(file_spec.GetPath(), true);
44 error.SetErrorString(err_code.message().c_str());
51 FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse)
54 std::wstring path_buffer;
55 if (!llvm::ConvertUTF8toWide(file_spec.GetPath(), path_buffer))
57 error.SetErrorString(PATH_CONVERSION_ERROR);
62 BOOL result = ::RemoveDirectoryW(path_buffer.c_str());
64 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
68 // SHFileOperation() accepts a list of paths, and so must be double-null-terminated to
69 // indicate the end of the list. The first null terminator is there only in the backing
70 // store but not the actual vector contents, and so we need to push twice.
71 path_buffer.push_back(0);
72 path_buffer.push_back(0);
74 SHFILEOPSTRUCTW shfos = {0};
75 shfos.wFunc = FO_DELETE;
76 shfos.pFrom = (LPCWSTR)path_buffer.data();
77 shfos.fFlags = FOF_NO_UI;
79 int result = ::SHFileOperationW(&shfos);
80 // TODO(zturner): Correctly handle the intricacies of SHFileOperation return values.
82 error.SetErrorStringWithFormat("SHFileOperation failed");
88 FileSystem::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions)
91 // Beware that Windows's permission model is different from Unix's, and it's
92 // not clear if this API is supposed to check ACLs. To match the caller's
93 // expectations as closely as possible, we'll use Microsoft's _stat, which
94 // attempts to emulate POSIX stat. This should be good enough for basic
95 // checks like FileSpec::Readable.
96 struct _stat file_stats;
97 if (::_stat(file_spec.GetCString(), &file_stats) == 0)
99 // The owner permission bits in "st_mode" currently match the definitions
100 // for the owner file mode bits.
101 file_permissions = file_stats.st_mode & (_S_IREAD | _S_IWRITE | _S_IEXEC);
105 error.SetErrorToErrno();
112 FileSystem::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions)
115 error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
120 FileSystem::GetFileSize(const FileSpec &file_spec)
122 return file_spec.GetByteSize();
126 FileSystem::GetFileExists(const FileSpec &file_spec)
128 return file_spec.Exists();
132 FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst)
135 std::wstring wsrc, wdst;
136 if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) || !llvm::ConvertUTF8toWide(dst.GetCString(), wdst))
137 error.SetErrorString(PATH_CONVERSION_ERROR);
138 else if (!::CreateHardLinkW(wsrc.c_str(), wdst.c_str(), nullptr))
139 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
144 FileSystem::GetHardlinkCount(const FileSpec &file_spec)
147 if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path))
150 HANDLE file_handle = ::CreateFileW(path.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
151 FILE_ATTRIBUTE_NORMAL, nullptr);
153 if (file_handle == INVALID_HANDLE_VALUE)
156 AutoHandle auto_file_handle(file_handle);
157 BY_HANDLE_FILE_INFORMATION file_info;
158 if (::GetFileInformationByHandle(file_handle, &file_info))
159 return file_info.nNumberOfLinks;
165 FileSystem::Symlink(const FileSpec &src, const FileSpec &dst)
168 std::wstring wsrc, wdst;
169 if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) || !llvm::ConvertUTF8toWide(dst.GetCString(), wdst))
170 error.SetErrorString(PATH_CONVERSION_ERROR);
173 DWORD attrib = ::GetFileAttributesW(wdst.c_str());
174 if (attrib == INVALID_FILE_ATTRIBUTES)
176 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
179 bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY);
180 DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
181 BOOL result = ::CreateSymbolicLinkW(wsrc.c_str(), wdst.c_str(), flag);
183 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
188 FileSystem::Unlink(const FileSpec &file_spec)
192 if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path))
194 error.SetErrorString(PATH_CONVERSION_ERROR);
197 BOOL result = ::DeleteFileW(path.c_str());
199 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
204 FileSystem::Readlink(const FileSpec &src, FileSpec &dst)
208 if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc))
210 error.SetErrorString(PATH_CONVERSION_ERROR);
214 HANDLE h = ::CreateFileW(wsrc.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
215 FILE_FLAG_OPEN_REPARSE_POINT, NULL);
216 if (h == INVALID_HANDLE_VALUE)
218 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
222 std::vector<wchar_t> buf(PATH_MAX + 1);
223 // Subtract 1 from the path length since this function does not add a null terminator.
224 DWORD result = ::GetFinalPathNameByHandleW(h, buf.data(), buf.size() - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
227 error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
228 else if (!llvm::convertWideToUTF8(buf.data(), path))
229 error.SetErrorString(PATH_CONVERSION_ERROR);
231 dst.SetFile(path, false);
238 FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst)
240 return Error("ResolveSymbolicLink() isn't implemented on Windows");
244 FileSystem::IsLocal(const FileSpec &spec)
248 // TODO: return true if the file is on a locally mounted file system
256 FileSystem::Fopen(const char *path, const char *mode)
258 std::wstring wpath, wmode;
259 if (!llvm::ConvertUTF8toWide(path, wpath))
261 if (!llvm::ConvertUTF8toWide(mode, wmode))
264 if (_wfopen_s(&file, wpath.c_str(), wmode.c_str()) != 0)
270 FileSystem::Stat(const char *path, struct stat *stats)
273 if (!llvm::ConvertUTF8toWide(path, wpath))
279 #ifdef _USE_32BIT_TIME_T
280 struct _stat32 file_stats;
281 stat_result = ::_wstat32(wpath.c_str(), &file_stats);
283 struct _stat64i32 file_stats;
284 stat_result = ::_wstat64i32(wpath.c_str(), &file_stats);
286 if (stat_result == 0)
288 static_assert(sizeof(struct stat) == sizeof(file_stats),
289 "stat and _stat32/_stat64i32 must have the same layout");
290 *stats = *reinterpret_cast<struct stat *>(&file_stats);