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 <sys/stat.h> 14 #include <sys/types.h> 15 16 // lldb Includes 17 #include "lldb/Core/Error.h" 18 #include "lldb/Core/StreamString.h" 19 #include "lldb/Host/Host.h" 20 21 using namespace lldb; 22 using namespace lldb_private; 23 24 FileSpec::PathSyntax 25 FileSystem::GetNativePathSyntax() 26 { 27 return FileSpec::ePathSyntaxPosix; 28 } 29 30 Error 31 FileSystem::MakeDirectory(const char *path, uint32_t file_permissions) 32 { 33 Error error; 34 if (path && path[0]) 35 { 36 if (::mkdir(path, file_permissions) != 0) 37 { 38 error.SetErrorToErrno(); 39 switch (error.GetError()) 40 { 41 case ENOENT: 42 { 43 // Parent directory doesn't exist, so lets make it if we can 44 FileSpec spec(path, false); 45 if (spec.GetDirectory() && spec.GetFilename()) 46 { 47 // Make the parent directory and try again 48 Error error2 = MakeDirectory(spec.GetDirectory().GetCString(), file_permissions); 49 if (error2.Success()) 50 { 51 // Try and make the directory again now that the parent directory was made successfully 52 if (::mkdir(path, file_permissions) == 0) 53 error.Clear(); 54 else 55 error.SetErrorToErrno(); 56 } 57 } 58 } 59 break; 60 61 case EEXIST: 62 { 63 FileSpec path_spec(path, false); 64 if (path_spec.IsDirectory()) 65 error.Clear(); // It is a directory and it already exists 66 } 67 break; 68 } 69 } 70 } 71 else 72 { 73 error.SetErrorString("empty path"); 74 } 75 return error; 76 } 77 78 Error 79 FileSystem::DeleteDirectory(const char *path, bool recurse) 80 { 81 Error error; 82 if (path && path[0]) 83 { 84 if (recurse) 85 { 86 StreamString command; 87 command.Printf("rm -rf \"%s\"", path); 88 int status = ::system(command.GetString().c_str()); 89 if (status != 0) 90 error.SetError(status, eErrorTypeGeneric); 91 } 92 else 93 { 94 if (::rmdir(path) != 0) 95 error.SetErrorToErrno(); 96 } 97 } 98 else 99 { 100 error.SetErrorString("empty path"); 101 } 102 return error; 103 } 104 105 Error 106 FileSystem::GetFilePermissions(const char *path, uint32_t &file_permissions) 107 { 108 Error error; 109 struct stat file_stats; 110 if (::stat(path, &file_stats) == 0) 111 { 112 // The bits in "st_mode" currently match the definitions 113 // for the file mode bits in unix. 114 file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 115 } 116 else 117 { 118 error.SetErrorToErrno(); 119 } 120 return error; 121 } 122 123 Error 124 FileSystem::SetFilePermissions(const char *path, uint32_t file_permissions) 125 { 126 Error error; 127 if (::chmod(path, file_permissions) != 0) 128 error.SetErrorToErrno(); 129 return error; 130 } 131 132 lldb::user_id_t 133 FileSystem::GetFileSize(const FileSpec &file_spec) 134 { 135 return file_spec.GetByteSize(); 136 } 137 138 bool 139 FileSystem::GetFileExists(const FileSpec &file_spec) 140 { 141 return file_spec.Exists(); 142 } 143 144 Error 145 FileSystem::Symlink(const char *src, const char *dst) 146 { 147 Error error; 148 if (::symlink(dst, src) == -1) 149 error.SetErrorToErrno(); 150 return error; 151 } 152 153 Error 154 FileSystem::Unlink(const char *path) 155 { 156 Error error; 157 if (::unlink(path) == -1) 158 error.SetErrorToErrno(); 159 return error; 160 } 161 162 Error 163 FileSystem::Readlink(const char *path, char *buf, size_t buf_len) 164 { 165 Error error; 166 ssize_t count = ::readlink(path, buf, buf_len); 167 if (count < 0) 168 error.SetErrorToErrno(); 169 else if (static_cast<size_t>(count) < (buf_len - 1)) 170 buf[count] = '\0'; // Success 171 else 172 error.SetErrorString("'buf' buffer is too small to contain link contents"); 173 return error; 174 } 175 176 bool 177 FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high) 178 { 179 #if defined(__APPLE__) 180 StreamString md5_cmd_line; 181 md5_cmd_line.Printf("md5 -q '%s'", file_spec.GetPath().c_str()); 182 std::string hash_string; 183 Error err = Host::RunShellCommand(md5_cmd_line.GetData(), NULL, NULL, NULL, &hash_string, 60); 184 if (err.Fail()) 185 return false; 186 // a correctly formed MD5 is 16-bytes, that is 32 hex digits 187 // if the output is any other length it is probably wrong 188 if (hash_string.size() != 32) 189 return false; 190 std::string part1(hash_string, 0, 16); 191 std::string part2(hash_string, 16); 192 const char *part1_cstr = part1.c_str(); 193 const char *part2_cstr = part2.c_str(); 194 high = ::strtoull(part1_cstr, NULL, 16); 195 low = ::strtoull(part2_cstr, NULL, 16); 196 return true; 197 #else 198 // your own MD5 implementation here 199 return false; 200 #endif 201 } 202