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 33 FileSystem::GetNativePathSyntax() 34 { 35 return FileSpec::ePathSyntaxPosix; 36 } 37 38 Error 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 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 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 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 162 FileSystem::GetFileSize(const FileSpec &file_spec) 163 { 164 return file_spec.GetByteSize(); 165 } 166 167 bool 168 FileSystem::GetFileExists(const FileSpec &file_spec) 169 { 170 return file_spec.Exists(); 171 } 172 173 Error 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 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 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 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 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 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