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/FileSystem.h"
11
12 // C includes
13 #include <dirent.h>
14 #include <sys/mount.h>
15 #include <sys/param.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #ifdef __linux__
19 #include <sys/statfs.h>
20 #include <sys/mount.h>
21 #include <linux/magic.h>
22 #endif
23
24 // lldb Includes
25 #include "lldb/Core/Error.h"
26 #include "lldb/Core/StreamString.h"
27 #include "lldb/Host/Host.h"
28
29 using namespace lldb;
30 using namespace lldb_private;
31
32 FileSpec::PathSyntax
GetNativePathSyntax()33 FileSystem::GetNativePathSyntax()
34 {
35 return FileSpec::ePathSyntaxPosix;
36 }
37
38 Error
MakeDirectory(const FileSpec & file_spec,uint32_t file_permissions)39 FileSystem::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions)
40 {
41 if (file_spec)
42 {
43 Error error;
44 if (::mkdir(file_spec.GetCString(), file_permissions) == -1)
45 {
46 error.SetErrorToErrno();
47 errno = 0;
48 switch (error.GetError())
49 {
50 case ENOENT:
51 {
52 // Parent directory doesn't exist, so lets make it if we can
53 // Make the parent directory and try again
54 FileSpec parent_file_spec{file_spec.GetDirectory().GetCString(), false};
55 error = MakeDirectory(parent_file_spec, file_permissions);
56 if (error.Fail())
57 return error;
58 // Try and make the directory again now that the parent directory was made successfully
59 if (::mkdir(file_spec.GetCString(), file_permissions) == -1)
60 {
61 error.SetErrorToErrno();
62 return error;
63 }
64 }
65 case EEXIST:
66 {
67 if (file_spec.IsDirectory())
68 return Error{}; // It is a directory and it already exists
69 }
70 }
71 }
72 return error;
73 }
74 return Error{"empty path"};
75 }
76
77 Error
DeleteDirectory(const FileSpec & file_spec,bool recurse)78 FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse)
79 {
80 Error error;
81 if (file_spec)
82 {
83 if (recurse)
84 {
85 // Save all sub directories in a list so we don't recursively call this function
86 // and possibly run out of file descriptors if the directory is too deep.
87 std::vector<FileSpec> sub_directories;
88
89 FileSpec::ForEachItemInDirectory (file_spec.GetCString(), [&error, &sub_directories](FileSpec::FileType file_type, const FileSpec &spec) -> FileSpec::EnumerateDirectoryResult {
90 if (file_type == FileSpec::eFileTypeDirectory)
91 {
92 // Save all directorires and process them after iterating through this directory
93 sub_directories.push_back(spec);
94 }
95 else
96 {
97 // Update sub_spec to point to the current file and delete it
98 error = FileSystem::Unlink(spec);
99 }
100 // If anything went wrong, stop iterating, else process the next file
101 if (error.Fail())
102 return FileSpec::eEnumerateDirectoryResultQuit;
103 else
104 return FileSpec::eEnumerateDirectoryResultNext;
105 });
106
107 if (error.Success())
108 {
109 // Now delete all sub directories with separate calls that aren't
110 // recursively calling into this function _while_ this function is
111 // iterating through the current directory.
112 for (const auto &sub_directory : sub_directories)
113 {
114 error = DeleteDirectory(sub_directory, recurse);
115 if (error.Fail())
116 break;
117 }
118 }
119 }
120
121 if (error.Success())
122 {
123 if (::rmdir(file_spec.GetCString()) != 0)
124 error.SetErrorToErrno();
125 }
126 }
127 else
128 {
129 error.SetErrorString("empty path");
130 }
131 return error;
132 }
133
134 Error
GetFilePermissions(const FileSpec & file_spec,uint32_t & file_permissions)135 FileSystem::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions)
136 {
137 Error error;
138 struct stat file_stats;
139 if (::stat(file_spec.GetCString(), &file_stats) == 0)
140 {
141 // The bits in "st_mode" currently match the definitions
142 // for the file mode bits in unix.
143 file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
144 }
145 else
146 {
147 error.SetErrorToErrno();
148 }
149 return error;
150 }
151
152 Error
SetFilePermissions(const FileSpec & file_spec,uint32_t file_permissions)153 FileSystem::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions)
154 {
155 Error error;
156 if (::chmod(file_spec.GetCString(), file_permissions) != 0)
157 error.SetErrorToErrno();
158 return error;
159 }
160
161 lldb::user_id_t
GetFileSize(const FileSpec & file_spec)162 FileSystem::GetFileSize(const FileSpec &file_spec)
163 {
164 return file_spec.GetByteSize();
165 }
166
167 bool
GetFileExists(const FileSpec & file_spec)168 FileSystem::GetFileExists(const FileSpec &file_spec)
169 {
170 return file_spec.Exists();
171 }
172
173 Error
Hardlink(const FileSpec & src,const FileSpec & dst)174 FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst)
175 {
176 Error error;
177 if (::link(dst.GetCString(), src.GetCString()) == -1)
178 error.SetErrorToErrno();
179 return error;
180 }
181
182 Error
Symlink(const FileSpec & src,const FileSpec & dst)183 FileSystem::Symlink(const FileSpec &src, const FileSpec &dst)
184 {
185 Error error;
186 if (::symlink(dst.GetCString(), src.GetCString()) == -1)
187 error.SetErrorToErrno();
188 return error;
189 }
190
191 Error
Unlink(const FileSpec & file_spec)192 FileSystem::Unlink(const FileSpec &file_spec)
193 {
194 Error error;
195 if (::unlink(file_spec.GetCString()) == -1)
196 error.SetErrorToErrno();
197 return error;
198 }
199
200 Error
Readlink(const FileSpec & src,FileSpec & dst)201 FileSystem::Readlink(const FileSpec &src, FileSpec &dst)
202 {
203 Error error;
204 char buf[PATH_MAX];
205 ssize_t count = ::readlink(src.GetCString(), buf, sizeof(buf) - 1);
206 if (count < 0)
207 error.SetErrorToErrno();
208 else
209 {
210 buf[count] = '\0'; // Success
211 dst.SetFile(buf, false);
212 }
213 return error;
214 }
215
IsLocal(const struct statfs & info)216 static bool IsLocal(const struct statfs& info)
217 {
218 #ifdef __linux__
219 #define CIFS_MAGIC_NUMBER 0xFF534D42
220 switch ((uint32_t)info.f_type)
221 {
222 case NFS_SUPER_MAGIC:
223 case SMB_SUPER_MAGIC:
224 case CIFS_MAGIC_NUMBER:
225 return false;
226 default:
227 return true;
228 }
229 #else
230 return (info.f_flags & MNT_LOCAL) != 0;
231 #endif
232 }
233
234 bool
IsLocal(const FileSpec & spec)235 FileSystem::IsLocal(const FileSpec &spec)
236 {
237 struct statfs statfs_info;
238 std::string path (spec.GetPath());
239 if (statfs(path.c_str(), &statfs_info) == 0)
240 return ::IsLocal(statfs_info);
241 return false;
242 }
243