PlatformPOSIX.cpp revision 269024
1//===-- PlatformPOSIX.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 "PlatformPOSIX.h" 11 12// C Includes 13// C++ Includes 14// Other libraries and framework includes 15// Project includes 16 17#include "lldb/Core/DataBufferHeap.h" 18#include "lldb/Core/Log.h" 19#include "lldb/Core/StreamString.h" 20#include "lldb/Host/File.h" 21#include "lldb/Host/FileSpec.h" 22#include "lldb/Host/Host.h" 23 24using namespace lldb; 25using namespace lldb_private; 26 27 28//------------------------------------------------------------------ 29/// Default Constructor 30//------------------------------------------------------------------ 31PlatformPOSIX::PlatformPOSIX (bool is_host) : 32Platform(is_host), // This is the local host platform 33m_remote_platform_sp () 34{ 35} 36 37//------------------------------------------------------------------ 38/// Destructor. 39/// 40/// The destructor is virtual since this class is designed to be 41/// inherited from by the plug-in instance. 42//------------------------------------------------------------------ 43PlatformPOSIX::~PlatformPOSIX() 44{ 45} 46 47lldb_private::OptionGroupOptions* 48PlatformPOSIX::GetConnectionOptions (lldb_private::CommandInterpreter& interpreter) 49{ 50 if (m_options.get() == NULL) 51 { 52 m_options.reset(new OptionGroupOptions(interpreter)); 53 m_options->Append(new OptionGroupPlatformRSync()); 54 m_options->Append(new OptionGroupPlatformSSH()); 55 m_options->Append(new OptionGroupPlatformCaching()); 56 } 57 return m_options.get(); 58} 59 60lldb_private::Error 61PlatformPOSIX::RunShellCommand (const char *command, // Shouldn't be NULL 62 const char *working_dir, // Pass NULL to use the current working directory 63 int *status_ptr, // Pass NULL if you don't want the process exit status 64 int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit 65 std::string *command_output, // Pass NULL if you don't want the command output 66 uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish 67{ 68 if (IsHost()) 69 return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec); 70 else 71 { 72 if (m_remote_platform_sp) 73 return m_remote_platform_sp->RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec); 74 else 75 return Error("unable to run a remote command without a platform"); 76 } 77} 78 79Error 80PlatformPOSIX::MakeDirectory (const char *path, uint32_t file_permissions) 81{ 82 if (m_remote_platform_sp) 83 return m_remote_platform_sp->MakeDirectory(path, file_permissions); 84 else 85 return Platform::MakeDirectory(path ,file_permissions); 86} 87 88Error 89PlatformPOSIX::GetFilePermissions (const char *path, uint32_t &file_permissions) 90{ 91 if (m_remote_platform_sp) 92 return m_remote_platform_sp->GetFilePermissions(path, file_permissions); 93 else 94 return Platform::GetFilePermissions(path ,file_permissions); 95} 96 97Error 98PlatformPOSIX::SetFilePermissions (const char *path, uint32_t file_permissions) 99{ 100 if (m_remote_platform_sp) 101 return m_remote_platform_sp->MakeDirectory(path, file_permissions); 102 else 103 return Platform::SetFilePermissions(path ,file_permissions); 104} 105 106lldb::user_id_t 107PlatformPOSIX::OpenFile (const FileSpec& file_spec, 108 uint32_t flags, 109 uint32_t mode, 110 Error &error) 111{ 112 if (IsHost()) 113 return Host::OpenFile(file_spec, flags, mode, error); 114 else if (m_remote_platform_sp) 115 return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error); 116 else 117 return Platform::OpenFile(file_spec, flags, mode, error); 118} 119 120bool 121PlatformPOSIX::CloseFile (lldb::user_id_t fd, Error &error) 122{ 123 if (IsHost()) 124 return Host::CloseFile(fd, error); 125 else if (m_remote_platform_sp) 126 return m_remote_platform_sp->CloseFile(fd, error); 127 else 128 return Platform::CloseFile(fd, error); 129} 130 131uint64_t 132PlatformPOSIX::ReadFile (lldb::user_id_t fd, 133 uint64_t offset, 134 void *dst, 135 uint64_t dst_len, 136 Error &error) 137{ 138 if (IsHost()) 139 return Host::ReadFile(fd, offset, dst, dst_len, error); 140 else if (m_remote_platform_sp) 141 return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error); 142 else 143 return Platform::ReadFile(fd, offset, dst, dst_len, error); 144} 145 146uint64_t 147PlatformPOSIX::WriteFile (lldb::user_id_t fd, 148 uint64_t offset, 149 const void* src, 150 uint64_t src_len, 151 Error &error) 152{ 153 if (IsHost()) 154 return Host::WriteFile(fd, offset, src, src_len, error); 155 else if (m_remote_platform_sp) 156 return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error); 157 else 158 return Platform::WriteFile(fd, offset, src, src_len, error); 159} 160 161static uint32_t 162chown_file(Platform *platform, 163 const char* path, 164 uint32_t uid = UINT32_MAX, 165 uint32_t gid = UINT32_MAX) 166{ 167 if (!platform || !path || *path == 0) 168 return UINT32_MAX; 169 170 if (uid == UINT32_MAX && gid == UINT32_MAX) 171 return 0; // pretend I did chown correctly - actually I just didn't care 172 173 StreamString command; 174 command.PutCString("chown "); 175 if (uid != UINT32_MAX) 176 command.Printf("%d",uid); 177 if (gid != UINT32_MAX) 178 command.Printf(":%d",gid); 179 command.Printf("%s",path); 180 int status; 181 platform->RunShellCommand(command.GetData(), 182 NULL, 183 &status, 184 NULL, 185 NULL, 186 10); 187 return status; 188} 189 190lldb_private::Error 191PlatformPOSIX::PutFile (const lldb_private::FileSpec& source, 192 const lldb_private::FileSpec& destination, 193 uint32_t uid, 194 uint32_t gid) 195{ 196 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 197 198 if (IsHost()) 199 { 200 if (FileSpec::Equal(source, destination, true)) 201 return Error(); 202 // cp src dst 203 // chown uid:gid dst 204 std::string src_path (source.GetPath()); 205 if (src_path.empty()) 206 return Error("unable to get file path for source"); 207 std::string dst_path (destination.GetPath()); 208 if (dst_path.empty()) 209 return Error("unable to get file path for destination"); 210 StreamString command; 211 command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); 212 int status; 213 RunShellCommand(command.GetData(), 214 NULL, 215 &status, 216 NULL, 217 NULL, 218 10); 219 if (status != 0) 220 return Error("unable to perform copy"); 221 if (uid == UINT32_MAX && gid == UINT32_MAX) 222 return Error(); 223 if (chown_file(this,dst_path.c_str(),uid,gid) != 0) 224 return Error("unable to perform chown"); 225 return Error(); 226 } 227 else if (m_remote_platform_sp) 228 { 229 if (GetSupportsRSync()) 230 { 231 std::string src_path (source.GetPath()); 232 if (src_path.empty()) 233 return Error("unable to get file path for source"); 234 std::string dst_path (destination.GetPath()); 235 if (dst_path.empty()) 236 return Error("unable to get file path for destination"); 237 StreamString command; 238 if (GetIgnoresRemoteHostname()) 239 { 240 if (!GetRSyncPrefix()) 241 command.Printf("rsync %s %s %s", 242 GetRSyncOpts(), 243 src_path.c_str(), 244 dst_path.c_str()); 245 else 246 command.Printf("rsync %s %s %s%s", 247 GetRSyncOpts(), 248 src_path.c_str(), 249 GetRSyncPrefix(), 250 dst_path.c_str()); 251 } 252 else 253 command.Printf("rsync %s %s %s:%s", 254 GetRSyncOpts(), 255 src_path.c_str(), 256 GetHostname(), 257 dst_path.c_str()); 258 if (log) 259 log->Printf("[PutFile] Running command: %s\n", command.GetData()); 260 int retcode; 261 Host::RunShellCommand(command.GetData(), 262 NULL, 263 &retcode, 264 NULL, 265 NULL, 266 60); 267 if (retcode == 0) 268 { 269 // Don't chown a local file for a remote system 270// if (chown_file(this,dst_path.c_str(),uid,gid) != 0) 271// return Error("unable to perform chown"); 272 return Error(); 273 } 274 // if we are still here rsync has failed - let's try the slow way before giving up 275 } 276 277 if (log) 278 log->Printf ("PlatformPOSIX::PutFile(src='%s', dst='%s', uid=%u, gid=%u)", 279 source.GetPath().c_str(), 280 destination.GetPath().c_str(), 281 uid, 282 gid); // REMOVE THIS PRINTF PRIOR TO CHECKIN 283 // open 284 // read, write, read, write, ... 285 // close 286 // chown uid:gid dst 287 if (log) 288 log->Printf("[PutFile] Using block by block transfer....\n"); 289 290 uint32_t source_open_options = File::eOpenOptionRead; 291 if (source.GetFileType() == FileSpec::eFileTypeSymbolicLink) 292 source_open_options |= File::eOpenoptionDontFollowSymlinks; 293 294 File source_file(source, source_open_options, lldb::eFilePermissionsUserRW); 295 Error error; 296 uint32_t permissions = source_file.GetPermissions(error); 297 if (permissions == 0) 298 permissions = lldb::eFilePermissionsFileDefault; 299 300 if (!source_file.IsValid()) 301 return Error("unable to open source file"); 302 lldb::user_id_t dest_file = OpenFile (destination, 303 File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate, 304 permissions, 305 error); 306 if (log) 307 log->Printf ("dest_file = %" PRIu64 "\n", dest_file); 308 if (error.Fail()) 309 return error; 310 if (dest_file == UINT64_MAX) 311 return Error("unable to open target file"); 312 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); 313 uint64_t offset = 0; 314 while (error.Success()) 315 { 316 size_t bytes_read = buffer_sp->GetByteSize(); 317 error = source_file.Read(buffer_sp->GetBytes(), bytes_read); 318 if (bytes_read) 319 { 320 WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error); 321 offset += bytes_read; 322 } 323 else 324 break; 325 } 326 CloseFile(dest_file, error); 327 if (uid == UINT32_MAX && gid == UINT32_MAX) 328 return error; 329 // This is remopve, don't chown a local file... 330// std::string dst_path (destination.GetPath()); 331// if (chown_file(this,dst_path.c_str(),uid,gid) != 0) 332// return Error("unable to perform chown"); 333 return error; 334 } 335 return Platform::PutFile(source,destination,uid,gid); 336} 337 338lldb::user_id_t 339PlatformPOSIX::GetFileSize (const FileSpec& file_spec) 340{ 341 if (IsHost()) 342 return Host::GetFileSize(file_spec); 343 else if (m_remote_platform_sp) 344 return m_remote_platform_sp->GetFileSize(file_spec); 345 else 346 return Platform::GetFileSize(file_spec); 347} 348 349Error 350PlatformPOSIX::CreateSymlink(const char *src, const char *dst) 351{ 352 if (IsHost()) 353 return Host::Symlink(src, dst); 354 else if (m_remote_platform_sp) 355 return m_remote_platform_sp->CreateSymlink(src, dst); 356 else 357 return Platform::CreateSymlink(src, dst); 358} 359 360bool 361PlatformPOSIX::GetFileExists (const FileSpec& file_spec) 362{ 363 if (IsHost()) 364 return file_spec.Exists(); 365 else if (m_remote_platform_sp) 366 return m_remote_platform_sp->GetFileExists(file_spec); 367 else 368 return Platform::GetFileExists(file_spec); 369} 370 371Error 372PlatformPOSIX::Unlink (const char *path) 373{ 374 if (IsHost()) 375 return Host::Unlink (path); 376 else if (m_remote_platform_sp) 377 return m_remote_platform_sp->Unlink(path); 378 else 379 return Platform::Unlink(path); 380} 381 382lldb_private::Error 383PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path */, 384 const lldb_private::FileSpec& destination /* local file path */) 385{ 386 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); 387 388 // Check the args, first. 389 std::string src_path (source.GetPath()); 390 if (src_path.empty()) 391 return Error("unable to get file path for source"); 392 std::string dst_path (destination.GetPath()); 393 if (dst_path.empty()) 394 return Error("unable to get file path for destination"); 395 if (IsHost()) 396 { 397 if (FileSpec::Equal(source, destination, true)) 398 return Error("local scenario->source and destination are the same file path: no operation performed"); 399 // cp src dst 400 StreamString cp_command; 401 cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); 402 int status; 403 RunShellCommand(cp_command.GetData(), 404 NULL, 405 &status, 406 NULL, 407 NULL, 408 10); 409 if (status != 0) 410 return Error("unable to perform copy"); 411 return Error(); 412 } 413 else if (m_remote_platform_sp) 414 { 415 if (GetSupportsRSync()) 416 { 417 StreamString command; 418 if (GetIgnoresRemoteHostname()) 419 { 420 if (!GetRSyncPrefix()) 421 command.Printf("rsync %s %s %s", 422 GetRSyncOpts(), 423 src_path.c_str(), 424 dst_path.c_str()); 425 else 426 command.Printf("rsync %s %s%s %s", 427 GetRSyncOpts(), 428 GetRSyncPrefix(), 429 src_path.c_str(), 430 dst_path.c_str()); 431 } 432 else 433 command.Printf("rsync %s %s:%s %s", 434 GetRSyncOpts(), 435 m_remote_platform_sp->GetHostname(), 436 src_path.c_str(), 437 dst_path.c_str()); 438 if (log) 439 log->Printf("[GetFile] Running command: %s\n", command.GetData()); 440 int retcode; 441 Host::RunShellCommand(command.GetData(), 442 NULL, 443 &retcode, 444 NULL, 445 NULL, 446 60); 447 if (retcode == 0) 448 return Error(); 449 // If we are here, rsync has failed - let's try the slow way before giving up 450 } 451 // open src and dst 452 // read/write, read/write, read/write, ... 453 // close src 454 // close dst 455 if (log) 456 log->Printf("[GetFile] Using block by block transfer....\n"); 457 Error error; 458 user_id_t fd_src = OpenFile (source, 459 File::eOpenOptionRead, 460 lldb::eFilePermissionsFileDefault, 461 error); 462 463 if (fd_src == UINT64_MAX) 464 return Error("unable to open source file"); 465 466 uint32_t permissions = 0; 467 error = GetFilePermissions(source.GetPath().c_str(), permissions); 468 469 if (permissions == 0) 470 permissions = lldb::eFilePermissionsFileDefault; 471 472 user_id_t fd_dst = Host::OpenFile(destination, 473 File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate, 474 permissions, 475 error); 476 477 if (fd_dst == UINT64_MAX) 478 { 479 if (error.Success()) 480 error.SetErrorString("unable to open destination file"); 481 } 482 483 if (error.Success()) 484 { 485 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); 486 uint64_t offset = 0; 487 error.Clear(); 488 while (error.Success()) 489 { 490 const uint64_t n_read = ReadFile (fd_src, 491 offset, 492 buffer_sp->GetBytes(), 493 buffer_sp->GetByteSize(), 494 error); 495 if (error.Fail()) 496 break; 497 if (n_read == 0) 498 break; 499 if (Host::WriteFile(fd_dst, 500 offset, 501 buffer_sp->GetBytes(), 502 n_read, 503 error) != n_read) 504 { 505 if (!error.Fail()) 506 error.SetErrorString("unable to write to destination file"); 507 break; 508 } 509 offset += n_read; 510 } 511 } 512 // Ignore the close error of src. 513 if (fd_src != UINT64_MAX) 514 CloseFile(fd_src, error); 515 // And close the dst file descriptot. 516 if (fd_dst != UINT64_MAX && !Host::CloseFile(fd_dst, error)) 517 { 518 if (!error.Fail()) 519 error.SetErrorString("unable to close destination file"); 520 521 } 522 return error; 523 } 524 return Platform::GetFile(source,destination); 525} 526 527std::string 528PlatformPOSIX::GetPlatformSpecificConnectionInformation() 529{ 530 StreamString stream; 531 if (GetSupportsRSync()) 532 { 533 stream.PutCString("rsync"); 534 if ( (GetRSyncOpts() && *GetRSyncOpts()) || 535 (GetRSyncPrefix() && *GetRSyncPrefix()) || 536 GetIgnoresRemoteHostname()) 537 { 538 stream.Printf(", options: "); 539 if (GetRSyncOpts() && *GetRSyncOpts()) 540 stream.Printf("'%s' ",GetRSyncOpts()); 541 stream.Printf(", prefix: "); 542 if (GetRSyncPrefix() && *GetRSyncPrefix()) 543 stream.Printf("'%s' ",GetRSyncPrefix()); 544 if (GetIgnoresRemoteHostname()) 545 stream.Printf("ignore remote-hostname "); 546 } 547 } 548 if (GetSupportsSSH()) 549 { 550 stream.PutCString("ssh"); 551 if (GetSSHOpts() && *GetSSHOpts()) 552 stream.Printf(", options: '%s' ",GetSSHOpts()); 553 } 554 if (GetLocalCacheDirectory() && *GetLocalCacheDirectory()) 555 stream.Printf("cache dir: %s",GetLocalCacheDirectory()); 556 if (stream.GetSize()) 557 return stream.GetData(); 558 else 559 return ""; 560} 561 562bool 563PlatformPOSIX::CalculateMD5 (const FileSpec& file_spec, 564 uint64_t &low, 565 uint64_t &high) 566{ 567 if (IsHost()) 568 return Platform::CalculateMD5 (file_spec, low, high); 569 if (m_remote_platform_sp) 570 return m_remote_platform_sp->CalculateMD5(file_spec, low, high); 571 return false; 572} 573 574lldb_private::ConstString 575PlatformPOSIX::GetRemoteWorkingDirectory() 576{ 577 if (IsRemote() && m_remote_platform_sp) 578 return m_remote_platform_sp->GetRemoteWorkingDirectory(); 579 else 580 return Platform::GetRemoteWorkingDirectory(); 581} 582 583bool 584PlatformPOSIX::SetRemoteWorkingDirectory(const lldb_private::ConstString &path) 585{ 586 if (IsRemote() && m_remote_platform_sp) 587 return m_remote_platform_sp->SetRemoteWorkingDirectory(path); 588 else 589 return Platform::SetRemoteWorkingDirectory(path); 590} 591 592void 593PlatformPOSIX::CalculateTrapHandlerSymbolNames () 594{ 595 m_trap_handlers.push_back (ConstString ("_sigtramp")); 596} 597