1 //===-- FileSystem.cpp ------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Host/windows/windows.h"
11 
12 #include <shellapi.h>
13 
14 #include "lldb/Host/FileSystem.h"
15 #include "llvm/Support/FileSystem.h"
16 
17 using namespace lldb_private;
18 
19 FileSpec::PathSyntax
20 FileSystem::GetNativePathSyntax()
21 {
22     return FileSpec::ePathSyntaxWindows;
23 }
24 
25 Error
26 FileSystem::MakeDirectory(const char *path, uint32_t file_permissions)
27 {
28     // On Win32, the mode parameter is ignored, as Windows files and directories support a
29     // different permission model than POSIX.
30     Error error;
31     const auto err_code = llvm::sys::fs::create_directories(path, true);
32     if (err_code)
33     {
34         error.SetErrorString(err_code.message().c_str());
35     }
36 
37     return error;
38 }
39 
40 Error
41 FileSystem::DeleteDirectory(const char *path, bool recurse)
42 {
43     Error error;
44     if (!recurse)
45     {
46         BOOL result = ::RemoveDirectory(path);
47         if (!result)
48             error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
49     }
50     else
51     {
52         // SHFileOperation() accepts a list of paths, and so must be double-null-terminated to
53         // indicate the end of the list.
54         std::string path_buffer(path);
55         path_buffer.push_back(0);
56 
57         SHFILEOPSTRUCT shfos = {0};
58         shfos.wFunc = FO_DELETE;
59         shfos.pFrom = path_buffer.c_str();
60         shfos.fFlags = FOF_NO_UI;
61 
62         int result = ::SHFileOperation(&shfos);
63         // TODO(zturner): Correctly handle the intricacies of SHFileOperation return values.
64         if (result != 0)
65             error.SetErrorStringWithFormat("SHFileOperation failed");
66     }
67     return error;
68 }
69 
70 Error
71 FileSystem::GetFilePermissions(const char *path, uint32_t &file_permissions)
72 {
73     Error error;
74     error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
75     return error;
76 }
77 
78 Error
79 FileSystem::SetFilePermissions(const char *path, uint32_t file_permissions)
80 {
81     Error error;
82     error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
83     return error;
84 }
85 
86 lldb::user_id_t
87 FileSystem::GetFileSize(const FileSpec &file_spec)
88 {
89     return file_spec.GetByteSize();
90 }
91 
92 bool
93 FileSystem::GetFileExists(const FileSpec &file_spec)
94 {
95     return file_spec.Exists();
96 }
97 
98 Error
99 FileSystem::Symlink(const char *linkname, const char *target)
100 {
101     Error error;
102     DWORD attrib = ::GetFileAttributes(target);
103     if (attrib == INVALID_FILE_ATTRIBUTES)
104     {
105         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
106         return error;
107     }
108     bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY);
109     DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
110     BOOL result = ::CreateSymbolicLink(linkname, target, flag);
111     if (!result)
112         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
113     return error;
114 }
115 
116 Error
117 FileSystem::Unlink(const char *path)
118 {
119     Error error;
120     BOOL result = ::DeleteFile(path);
121     if (!result)
122         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
123     return error;
124 }
125 
126 Error
127 FileSystem::Readlink(const char *path, char *buf, size_t buf_len)
128 {
129     Error error;
130     HANDLE h = ::CreateFile(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
131                             FILE_FLAG_OPEN_REPARSE_POINT, NULL);
132     if (h == INVALID_HANDLE_VALUE)
133     {
134         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
135         return error;
136     }
137 
138     // Subtract 1 from the path length since this function does not add a null terminator.
139     DWORD result = ::GetFinalPathNameByHandle(h, buf, buf_len - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
140     if (result == 0)
141         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
142 
143     ::CloseHandle(h);
144     return error;
145 }
146 
147 bool
148 FileSystem::IsLocal(const FileSpec &spec)
149 {
150     if (spec)
151     {
152         // TODO: return true if the file is on a locally mounted file system
153         return true;
154     }
155 
156     return false;
157 }
158