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