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