1c00cf4a0SZachary Turner //===-- FileSystem.cpp ------------------------------------------*- C++ -*-===//
2c00cf4a0SZachary Turner //
3c00cf4a0SZachary Turner //                     The LLVM Compiler Infrastructure
4c00cf4a0SZachary Turner //
5c00cf4a0SZachary Turner // This file is distributed under the University of Illinois Open Source
6c00cf4a0SZachary Turner // License. See LICENSE.TXT for details.
7c00cf4a0SZachary Turner //
8c00cf4a0SZachary Turner //===----------------------------------------------------------------------===//
9c00cf4a0SZachary Turner 
10c00cf4a0SZachary Turner #include "lldb/Host/windows/windows.h"
11c00cf4a0SZachary Turner 
12c00cf4a0SZachary Turner #include <shellapi.h>
13*633594c2SAdrian McCarthy #include <sys/stat.h>
14*633594c2SAdrian McCarthy #include <sys/types.h>
15c00cf4a0SZachary Turner 
16c00cf4a0SZachary Turner #include "lldb/Host/FileSystem.h"
17cc815568SOleksiy Vyalov #include "llvm/Support/FileSystem.h"
18c00cf4a0SZachary Turner 
19c00cf4a0SZachary Turner using namespace lldb_private;
20c00cf4a0SZachary Turner 
21c00cf4a0SZachary Turner FileSpec::PathSyntax
22c00cf4a0SZachary Turner FileSystem::GetNativePathSyntax()
23c00cf4a0SZachary Turner {
24c00cf4a0SZachary Turner     return FileSpec::ePathSyntaxWindows;
25c00cf4a0SZachary Turner }
26c00cf4a0SZachary Turner 
27c00cf4a0SZachary Turner Error
28d3173f34SChaoren Lin FileSystem::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions)
29c00cf4a0SZachary Turner {
30c00cf4a0SZachary Turner     // On Win32, the mode parameter is ignored, as Windows files and directories support a
31c00cf4a0SZachary Turner     // different permission model than POSIX.
32c00cf4a0SZachary Turner     Error error;
33d3173f34SChaoren Lin     const auto err_code = llvm::sys::fs::create_directories(file_spec.GetPath(), true);
34cc815568SOleksiy Vyalov     if (err_code)
35cc815568SOleksiy Vyalov     {
36cc815568SOleksiy Vyalov         error.SetErrorString(err_code.message().c_str());
37cc815568SOleksiy Vyalov     }
38cc815568SOleksiy Vyalov 
39c00cf4a0SZachary Turner     return error;
40c00cf4a0SZachary Turner }
41c00cf4a0SZachary Turner 
42c00cf4a0SZachary Turner Error
43d3173f34SChaoren Lin FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse)
44c00cf4a0SZachary Turner {
45c00cf4a0SZachary Turner     Error error;
46c00cf4a0SZachary Turner     if (!recurse)
47c00cf4a0SZachary Turner     {
48d3173f34SChaoren Lin         BOOL result = ::RemoveDirectory(file_spec.GetCString());
49c00cf4a0SZachary Turner         if (!result)
50c00cf4a0SZachary Turner             error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
51c00cf4a0SZachary Turner     }
52c00cf4a0SZachary Turner     else
53c00cf4a0SZachary Turner     {
54c00cf4a0SZachary Turner         // SHFileOperation() accepts a list of paths, and so must be double-null-terminated to
55c00cf4a0SZachary Turner         // indicate the end of the list.
56d3173f34SChaoren Lin         std::string path_buffer{file_spec.GetPath()};
57c00cf4a0SZachary Turner         path_buffer.push_back(0);
58c00cf4a0SZachary Turner 
59c00cf4a0SZachary Turner         SHFILEOPSTRUCT shfos = {0};
60c00cf4a0SZachary Turner         shfos.wFunc = FO_DELETE;
61c00cf4a0SZachary Turner         shfos.pFrom = path_buffer.c_str();
62c00cf4a0SZachary Turner         shfos.fFlags = FOF_NO_UI;
63c00cf4a0SZachary Turner 
64c00cf4a0SZachary Turner         int result = ::SHFileOperation(&shfos);
65c00cf4a0SZachary Turner         // TODO(zturner): Correctly handle the intricacies of SHFileOperation return values.
66c00cf4a0SZachary Turner         if (result != 0)
67c00cf4a0SZachary Turner             error.SetErrorStringWithFormat("SHFileOperation failed");
68c00cf4a0SZachary Turner     }
69c00cf4a0SZachary Turner     return error;
70c00cf4a0SZachary Turner }
71c00cf4a0SZachary Turner 
72c00cf4a0SZachary Turner Error
73d3173f34SChaoren Lin FileSystem::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions)
74c00cf4a0SZachary Turner {
75c00cf4a0SZachary Turner     Error error;
76*633594c2SAdrian McCarthy     // Beware that Windows's permission model is different from Unix's, and it's
77*633594c2SAdrian McCarthy     // not clear if this API is supposed to check ACLs.  To match the caller's
78*633594c2SAdrian McCarthy     // expectations as closely as possible, we'll use Microsoft's _stat, which
79*633594c2SAdrian McCarthy     // attempts to emulate POSIX stat.  This should be good enough for basic
80*633594c2SAdrian McCarthy     // checks like FileSpec::Readable.
81*633594c2SAdrian McCarthy     struct _stat file_stats;
82*633594c2SAdrian McCarthy     if (::_stat(file_spec.GetCString(), &file_stats) == 0)
83*633594c2SAdrian McCarthy     {
84*633594c2SAdrian McCarthy         // The owner permission bits in "st_mode" currently match the definitions
85*633594c2SAdrian McCarthy         // for the owner file mode bits.
86*633594c2SAdrian McCarthy         file_permissions = file_stats.st_mode & (_S_IREAD | _S_IWRITE | _S_IEXEC);
87*633594c2SAdrian McCarthy     }
88*633594c2SAdrian McCarthy     else
89*633594c2SAdrian McCarthy     {
90*633594c2SAdrian McCarthy         error.SetErrorToErrno();
91*633594c2SAdrian McCarthy     }
92*633594c2SAdrian McCarthy 
93c00cf4a0SZachary Turner     return error;
94c00cf4a0SZachary Turner }
95c00cf4a0SZachary Turner 
96c00cf4a0SZachary Turner Error
97d3173f34SChaoren Lin FileSystem::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions)
98c00cf4a0SZachary Turner {
99c00cf4a0SZachary Turner     Error error;
100c00cf4a0SZachary Turner     error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
101c00cf4a0SZachary Turner     return error;
102c00cf4a0SZachary Turner }
103c00cf4a0SZachary Turner 
104c00cf4a0SZachary Turner lldb::user_id_t
105c00cf4a0SZachary Turner FileSystem::GetFileSize(const FileSpec &file_spec)
106c00cf4a0SZachary Turner {
107c00cf4a0SZachary Turner     return file_spec.GetByteSize();
108c00cf4a0SZachary Turner }
109c00cf4a0SZachary Turner 
110c00cf4a0SZachary Turner bool
111c00cf4a0SZachary Turner FileSystem::GetFileExists(const FileSpec &file_spec)
112c00cf4a0SZachary Turner {
113c00cf4a0SZachary Turner     return file_spec.Exists();
114c00cf4a0SZachary Turner }
115c00cf4a0SZachary Turner 
116c00cf4a0SZachary Turner Error
117d3173f34SChaoren Lin FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst)
118a9ea0711SOleksiy Vyalov {
119a9ea0711SOleksiy Vyalov     Error error;
120d3173f34SChaoren Lin     if (!::CreateHardLink(src.GetCString(), dst.GetCString(), nullptr))
121a9ea0711SOleksiy Vyalov         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
122a9ea0711SOleksiy Vyalov     return error;
123a9ea0711SOleksiy Vyalov }
124a9ea0711SOleksiy Vyalov 
125a9ea0711SOleksiy Vyalov Error
126d3173f34SChaoren Lin FileSystem::Symlink(const FileSpec &src, const FileSpec &dst)
127c00cf4a0SZachary Turner {
128c00cf4a0SZachary Turner     Error error;
129d3173f34SChaoren Lin     DWORD attrib = ::GetFileAttributes(dst.GetCString());
130c00cf4a0SZachary Turner     if (attrib == INVALID_FILE_ATTRIBUTES)
131c00cf4a0SZachary Turner     {
132c00cf4a0SZachary Turner         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
133c00cf4a0SZachary Turner         return error;
134c00cf4a0SZachary Turner     }
135c00cf4a0SZachary Turner     bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY);
136c00cf4a0SZachary Turner     DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
137d3173f34SChaoren Lin     BOOL result = ::CreateSymbolicLink(src.GetCString(), dst.GetCString(), flag);
138c00cf4a0SZachary Turner     if (!result)
139c00cf4a0SZachary Turner         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
140c00cf4a0SZachary Turner     return error;
141c00cf4a0SZachary Turner }
142c00cf4a0SZachary Turner 
143c00cf4a0SZachary Turner Error
144d3173f34SChaoren Lin FileSystem::Unlink(const FileSpec &file_spec)
145c00cf4a0SZachary Turner {
146c00cf4a0SZachary Turner     Error error;
147d3173f34SChaoren Lin     BOOL result = ::DeleteFile(file_spec.GetCString());
148c00cf4a0SZachary Turner     if (!result)
149c00cf4a0SZachary Turner         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
150c00cf4a0SZachary Turner     return error;
151c00cf4a0SZachary Turner }
152c00cf4a0SZachary Turner 
153c00cf4a0SZachary Turner Error
154d3173f34SChaoren Lin FileSystem::Readlink(const FileSpec &src, FileSpec &dst)
155c00cf4a0SZachary Turner {
156c00cf4a0SZachary Turner     Error error;
157d3173f34SChaoren Lin     HANDLE h = ::CreateFile(src.GetCString(), GENERIC_READ,
158d3173f34SChaoren Lin             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
159c00cf4a0SZachary Turner             FILE_FLAG_OPEN_REPARSE_POINT, NULL);
160c00cf4a0SZachary Turner     if (h == INVALID_HANDLE_VALUE)
161c00cf4a0SZachary Turner     {
162c00cf4a0SZachary Turner         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
163c00cf4a0SZachary Turner         return error;
164c00cf4a0SZachary Turner     }
165c00cf4a0SZachary Turner 
166d3173f34SChaoren Lin     char buf[PATH_MAX];
167c00cf4a0SZachary Turner     // Subtract 1 from the path length since this function does not add a null terminator.
168d3173f34SChaoren Lin     DWORD result = ::GetFinalPathNameByHandle(h, buf, sizeof(buf) - 1,
169d3173f34SChaoren Lin             FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
170c00cf4a0SZachary Turner     if (result == 0)
171c00cf4a0SZachary Turner         error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
172d3173f34SChaoren Lin     else
173d3173f34SChaoren Lin         dst.SetFile(buf, false);
174c00cf4a0SZachary Turner 
175c00cf4a0SZachary Turner     ::CloseHandle(h);
176c00cf4a0SZachary Turner     return error;
177c00cf4a0SZachary Turner }
178736888c8SGreg Clayton 
179736888c8SGreg Clayton bool
180736888c8SGreg Clayton FileSystem::IsLocal(const FileSpec &spec)
181736888c8SGreg Clayton {
182736888c8SGreg Clayton     if (spec)
183736888c8SGreg Clayton     {
184736888c8SGreg Clayton         // TODO: return true if the file is on a locally mounted file system
185736888c8SGreg Clayton         return true;
186736888c8SGreg Clayton     }
187736888c8SGreg Clayton 
188736888c8SGreg Clayton     return false;
189736888c8SGreg Clayton }
190