Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 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 |
Chaoren Lin | 226937e | 2015-06-27 23:11:34 +0000 | [diff] [blame] | 13 | #include <dirent.h> |
Greg Clayton | 736888c | 2015-02-23 23:47:09 +0000 | [diff] [blame] | 14 | #include <sys/mount.h> |
| 15 | #include <sys/param.h> |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 16 | #include <sys/stat.h> |
| 17 | #include <sys/types.h> |
Vince Harron | 294aeb9 | 2015-02-24 05:14:49 +0000 | [diff] [blame] | 18 | #ifdef __linux__ |
Vince Harron | 294aeb9 | 2015-02-24 05:14:49 +0000 | [diff] [blame] | 19 | #include <linux/magic.h> |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 20 | #include <sys/mount.h> |
| 21 | #include <sys/statfs.h> |
Vince Harron | 294aeb9 | 2015-02-24 05:14:49 +0000 | [diff] [blame] | 22 | #endif |
Stephane Sezer | 851f23d | 2015-09-09 01:19:05 +0000 | [diff] [blame] | 23 | #if defined(__NetBSD__) |
| 24 | #include <sys/statvfs.h> |
| 25 | #endif |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 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 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 35 | const char *FileSystem::DEV_NULL = "/dev/null"; |
Zachary Turner | 4eff2d3 | 2015-10-14 21:37:36 +0000 | [diff] [blame] | 36 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 37 | FileSpec::PathSyntax FileSystem::GetNativePathSyntax() { |
| 38 | return FileSpec::ePathSyntaxPosix; |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 39 | } |
| 40 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 41 | Error FileSystem::MakeDirectory(const FileSpec &file_spec, |
| 42 | uint32_t file_permissions) { |
| 43 | if (file_spec) { |
| 44 | Error error; |
| 45 | if (::mkdir(file_spec.GetCString(), file_permissions) == -1) { |
| 46 | error.SetErrorToErrno(); |
| 47 | errno = 0; |
| 48 | switch (error.GetError()) { |
| 49 | case ENOENT: { |
| 50 | // Parent directory doesn't exist, so lets make it if we can |
| 51 | // Make the parent directory and try again |
| 52 | FileSpec parent_file_spec{file_spec.GetDirectory().GetCString(), false}; |
| 53 | error = MakeDirectory(parent_file_spec, file_permissions); |
| 54 | if (error.Fail()) |
| 55 | return error; |
| 56 | // Try and make the directory again now that the parent directory was |
| 57 | // made successfully |
| 58 | if (::mkdir(file_spec.GetCString(), file_permissions) == -1) { |
| 59 | error.SetErrorToErrno(); |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 60 | } |
Chaoren Lin | d3173f3 | 2015-05-29 19:52:29 +0000 | [diff] [blame] | 61 | return error; |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 62 | } break; |
| 63 | case EEXIST: { |
| 64 | if (file_spec.IsDirectory()) |
| 65 | return Error(); // It is a directory and it already exists |
| 66 | } break; |
| 67 | } |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 68 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 69 | return error; |
| 70 | } |
| 71 | return Error("empty path"); |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 72 | } |
| 73 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 74 | Error FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse) { |
| 75 | Error error; |
| 76 | if (file_spec) { |
| 77 | if (recurse) { |
| 78 | // Save all sub directories in a list so we don't recursively call this |
| 79 | // function |
| 80 | // and possibly run out of file descriptors if the directory is too deep. |
| 81 | std::vector<FileSpec> sub_directories; |
Greg Clayton | 58c65f0 | 2015-06-29 18:29:00 +0000 | [diff] [blame] | 82 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 83 | FileSpec::ForEachItemInDirectory( |
| 84 | file_spec.GetCString(), |
| 85 | [&error, &sub_directories]( |
| 86 | FileSpec::FileType file_type, |
| 87 | const FileSpec &spec) -> FileSpec::EnumerateDirectoryResult { |
| 88 | if (file_type == FileSpec::eFileTypeDirectory) { |
| 89 | // Save all directorires and process them after iterating through |
| 90 | // this directory |
| 91 | sub_directories.push_back(spec); |
| 92 | } else { |
| 93 | // Update sub_spec to point to the current file and delete it |
| 94 | error = FileSystem::Unlink(spec); |
Chaoren Lin | 226937e | 2015-06-27 23:11:34 +0000 | [diff] [blame] | 95 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 96 | // If anything went wrong, stop iterating, else process the next |
| 97 | // file |
| 98 | if (error.Fail()) |
| 99 | return FileSpec::eEnumerateDirectoryResultQuit; |
| 100 | else |
| 101 | return FileSpec::eEnumerateDirectoryResultNext; |
| 102 | }); |
| 103 | |
| 104 | if (error.Success()) { |
| 105 | // Now delete all sub directories with separate calls that aren't |
| 106 | // recursively calling into this function _while_ this function is |
| 107 | // iterating through the current directory. |
| 108 | for (const auto &sub_directory : sub_directories) { |
| 109 | error = DeleteDirectory(sub_directory, recurse); |
| 110 | if (error.Fail()) |
| 111 | break; |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 112 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 113 | } |
| 114 | } |
Greg Clayton | 58c65f0 | 2015-06-29 18:29:00 +0000 | [diff] [blame] | 115 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 116 | if (error.Success()) { |
| 117 | if (::rmdir(file_spec.GetCString()) != 0) |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 118 | error.SetErrorToErrno(); |
| 119 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 120 | } else { |
| 121 | error.SetErrorString("empty path"); |
| 122 | } |
| 123 | return error; |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 124 | } |
| 125 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 126 | Error FileSystem::GetFilePermissions(const FileSpec &file_spec, |
| 127 | uint32_t &file_permissions) { |
| 128 | Error error; |
| 129 | struct stat file_stats; |
| 130 | if (::stat(file_spec.GetCString(), &file_stats) == 0) { |
| 131 | // The bits in "st_mode" currently match the definitions |
| 132 | // for the file mode bits in unix. |
| 133 | file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); |
| 134 | } else { |
| 135 | error.SetErrorToErrno(); |
| 136 | } |
| 137 | return error; |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 138 | } |
| 139 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 140 | Error FileSystem::SetFilePermissions(const FileSpec &file_spec, |
| 141 | uint32_t file_permissions) { |
| 142 | Error error; |
| 143 | if (::chmod(file_spec.GetCString(), file_permissions) != 0) |
| 144 | error.SetErrorToErrno(); |
| 145 | return error; |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 146 | } |
| 147 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 148 | lldb::user_id_t FileSystem::GetFileSize(const FileSpec &file_spec) { |
| 149 | return file_spec.GetByteSize(); |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 150 | } |
| 151 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 152 | bool FileSystem::GetFileExists(const FileSpec &file_spec) { |
| 153 | return file_spec.Exists(); |
Oleksiy Vyalov | a9ea071 | 2015-05-08 23:54:34 +0000 | [diff] [blame] | 154 | } |
| 155 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 156 | Error FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) { |
| 157 | Error error; |
| 158 | if (::link(dst.GetCString(), src.GetCString()) == -1) |
| 159 | error.SetErrorToErrno(); |
| 160 | return error; |
Oleksiy Vyalov | 2b38f33 | 2015-09-18 18:12:39 +0000 | [diff] [blame] | 161 | } |
| 162 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 163 | int FileSystem::GetHardlinkCount(const FileSpec &file_spec) { |
| 164 | struct stat file_stat; |
| 165 | if (::stat(file_spec.GetCString(), &file_stat) == 0) |
| 166 | return file_stat.st_nlink; |
| 167 | |
| 168 | return -1; |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 169 | } |
| 170 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 171 | Error FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) { |
| 172 | Error error; |
| 173 | if (::symlink(dst.GetCString(), src.GetCString()) == -1) |
| 174 | error.SetErrorToErrno(); |
| 175 | return error; |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 176 | } |
| 177 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 178 | Error FileSystem::Unlink(const FileSpec &file_spec) { |
| 179 | Error error; |
| 180 | if (::unlink(file_spec.GetCString()) == -1) |
| 181 | error.SetErrorToErrno(); |
| 182 | return error; |
Zachary Turner | c00cf4a | 2014-08-15 22:04:21 +0000 | [diff] [blame] | 183 | } |
Greg Clayton | 736888c | 2015-02-23 23:47:09 +0000 | [diff] [blame] | 184 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 185 | Error FileSystem::Readlink(const FileSpec &src, FileSpec &dst) { |
| 186 | Error error; |
| 187 | char buf[PATH_MAX]; |
| 188 | ssize_t count = ::readlink(src.GetCString(), buf, sizeof(buf) - 1); |
| 189 | if (count < 0) |
| 190 | error.SetErrorToErrno(); |
| 191 | else { |
| 192 | buf[count] = '\0'; // Success |
| 193 | dst.SetFile(buf, false); |
| 194 | } |
| 195 | return error; |
| 196 | } |
| 197 | |
| 198 | Error FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) { |
| 199 | char resolved_path[PATH_MAX]; |
| 200 | if (!src.GetPath(resolved_path, sizeof(resolved_path))) { |
| 201 | return Error("Couldn't get the canonical path for %s", src.GetCString()); |
| 202 | } |
| 203 | |
| 204 | char real_path[PATH_MAX + 1]; |
| 205 | if (realpath(resolved_path, real_path) == nullptr) { |
| 206 | Error err; |
| 207 | err.SetErrorToErrno(); |
| 208 | return err; |
| 209 | } |
| 210 | |
| 211 | dst = FileSpec(real_path, false); |
| 212 | |
| 213 | return Error(); |
Sean Callanan | 9077e9f | 2015-09-18 22:24:57 +0000 | [diff] [blame] | 214 | } |
| 215 | |
Stephane Sezer | 851f23d | 2015-09-09 01:19:05 +0000 | [diff] [blame] | 216 | #if defined(__NetBSD__) |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 217 | static bool IsLocal(const struct statvfs &info) { |
| 218 | return (info.f_flag & MNT_LOCAL) != 0; |
Stephane Sezer | 851f23d | 2015-09-09 01:19:05 +0000 | [diff] [blame] | 219 | } |
| 220 | #else |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 221 | static bool IsLocal(const struct statfs &info) { |
Vince Harron | 294aeb9 | 2015-02-24 05:14:49 +0000 | [diff] [blame] | 222 | #ifdef __linux__ |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 223 | #define CIFS_MAGIC_NUMBER 0xFF534D42 |
| 224 | switch ((uint32_t)info.f_type) { |
| 225 | case NFS_SUPER_MAGIC: |
| 226 | case SMB_SUPER_MAGIC: |
| 227 | case CIFS_MAGIC_NUMBER: |
| 228 | return false; |
| 229 | default: |
| 230 | return true; |
| 231 | } |
Vince Harron | 294aeb9 | 2015-02-24 05:14:49 +0000 | [diff] [blame] | 232 | #else |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 233 | return (info.f_flags & MNT_LOCAL) != 0; |
Vince Harron | 294aeb9 | 2015-02-24 05:14:49 +0000 | [diff] [blame] | 234 | #endif |
| 235 | } |
Stephane Sezer | 851f23d | 2015-09-09 01:19:05 +0000 | [diff] [blame] | 236 | #endif |
Vince Harron | 294aeb9 | 2015-02-24 05:14:49 +0000 | [diff] [blame] | 237 | |
Stephane Sezer | 851f23d | 2015-09-09 01:19:05 +0000 | [diff] [blame] | 238 | #if defined(__NetBSD__) |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 239 | bool FileSystem::IsLocal(const FileSpec &spec) { |
| 240 | struct statvfs statfs_info; |
| 241 | std::string path(spec.GetPath()); |
| 242 | if (statvfs(path.c_str(), &statfs_info) == 0) |
| 243 | return ::IsLocal(statfs_info); |
| 244 | return false; |
Stephane Sezer | 851f23d | 2015-09-09 01:19:05 +0000 | [diff] [blame] | 245 | } |
| 246 | #else |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 247 | bool FileSystem::IsLocal(const FileSpec &spec) { |
| 248 | struct statfs statfs_info; |
| 249 | std::string path(spec.GetPath()); |
| 250 | if (statfs(path.c_str(), &statfs_info) == 0) |
| 251 | return ::IsLocal(statfs_info); |
| 252 | return false; |
Greg Clayton | 736888c | 2015-02-23 23:47:09 +0000 | [diff] [blame] | 253 | } |
Stephane Sezer | 851f23d | 2015-09-09 01:19:05 +0000 | [diff] [blame] | 254 | #endif |
Zachary Turner | 190fadc | 2016-03-22 17:58:09 +0000 | [diff] [blame] | 255 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 256 | FILE *FileSystem::Fopen(const char *path, const char *mode) { |
| 257 | return ::fopen(path, mode); |
Zachary Turner | 190fadc | 2016-03-22 17:58:09 +0000 | [diff] [blame] | 258 | } |
| 259 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 260 | int FileSystem::Stat(const char *path, struct stat *stats) { |
| 261 | return ::stat(path, stats); |
Zachary Turner | 190fadc | 2016-03-22 17:58:09 +0000 | [diff] [blame] | 262 | } |