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::Hardlink(const char *linkname, const char *target)
100 {
101     Error error;
102     if (!::CreateHardLink(linkname, target, nullptr))
103         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
104     return error;
105 }
106 
107 Error
108 FileSystem::Symlink(const char *linkname, const char *target)
109 {
110     Error error;
111     DWORD attrib = ::GetFileAttributes(target);
112     if (attrib == INVALID_FILE_ATTRIBUTES)
113     {
114         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
115         return error;
116     }
117     bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY);
118     DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
119     BOOL result = ::CreateSymbolicLink(linkname, target, flag);
120     if (!result)
121         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
122     return error;
123 }
124 
125 Error
126 FileSystem::Unlink(const char *path)
127 {
128     Error error;
129     BOOL result = ::DeleteFile(path);
130     if (!result)
131         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
132     return error;
133 }
134 
135 Error
136 FileSystem::Readlink(const char *path, char *buf, size_t buf_len)
137 {
138     Error error;
139     HANDLE h = ::CreateFile(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
140                             FILE_FLAG_OPEN_REPARSE_POINT, NULL);
141     if (h == INVALID_HANDLE_VALUE)
142     {
143         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
144         return error;
145     }
146 
147     // Subtract 1 from the path length since this function does not add a null terminator.
148     DWORD result = ::GetFinalPathNameByHandle(h, buf, buf_len - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
149     if (result == 0)
150         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
151 
152     ::CloseHandle(h);
153     return error;
154 }
155 
156 bool
157 FileSystem::IsLocal(const FileSpec &spec)
158 {
159     if (spec)
160     {
161         // TODO: return true if the file is on a locally mounted file system
162         return true;
163     }
164 
165     return false;
166 }
167