1 //===-- PlatformPOSIX.cpp ---------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "PlatformPOSIX.h"
14 // Other libraries and framework includes
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"
25 using namespace lldb_private;
28 //------------------------------------------------------------------
29 /// Default Constructor
30 //------------------------------------------------------------------
31 PlatformPOSIX::PlatformPOSIX (bool is_host) :
32 Platform(is_host), // This is the local host platform
33 m_remote_platform_sp ()
37 //------------------------------------------------------------------
40 /// The destructor is virtual since this class is designed to be
41 /// inherited from by the plug-in instance.
42 //------------------------------------------------------------------
43 PlatformPOSIX::~PlatformPOSIX()
47 lldb_private::OptionGroupOptions*
48 PlatformPOSIX::GetConnectionOptions (lldb_private::CommandInterpreter& interpreter)
50 if (m_options.get() == NULL)
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());
57 return m_options.get();
61 PlatformPOSIX::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
69 return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
72 if (m_remote_platform_sp)
73 return m_remote_platform_sp->RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec);
75 return Error("unable to run a remote command without a platform");
80 PlatformPOSIX::MakeDirectory (const char *path, uint32_t file_permissions)
82 if (m_remote_platform_sp)
83 return m_remote_platform_sp->MakeDirectory(path, file_permissions);
85 return Platform::MakeDirectory(path ,file_permissions);
89 PlatformPOSIX::GetFilePermissions (const char *path, uint32_t &file_permissions)
91 if (m_remote_platform_sp)
92 return m_remote_platform_sp->GetFilePermissions(path, file_permissions);
94 return Platform::GetFilePermissions(path ,file_permissions);
98 PlatformPOSIX::SetFilePermissions (const char *path, uint32_t file_permissions)
100 if (m_remote_platform_sp)
101 return m_remote_platform_sp->MakeDirectory(path, file_permissions);
103 return Platform::SetFilePermissions(path ,file_permissions);
107 PlatformPOSIX::OpenFile (const FileSpec& file_spec,
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);
117 return Platform::OpenFile(file_spec, flags, mode, error);
121 PlatformPOSIX::CloseFile (lldb::user_id_t fd, Error &error)
124 return Host::CloseFile(fd, error);
125 else if (m_remote_platform_sp)
126 return m_remote_platform_sp->CloseFile(fd, error);
128 return Platform::CloseFile(fd, error);
132 PlatformPOSIX::ReadFile (lldb::user_id_t fd,
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);
143 return Platform::ReadFile(fd, offset, dst, dst_len, error);
147 PlatformPOSIX::WriteFile (lldb::user_id_t fd,
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);
158 return Platform::WriteFile(fd, offset, src, src_len, error);
162 chown_file(Platform *platform,
164 uint32_t uid = UINT32_MAX,
165 uint32_t gid = UINT32_MAX)
167 if (!platform || !path || *path == 0)
170 if (uid == UINT32_MAX && gid == UINT32_MAX)
171 return 0; // pretend I did chown correctly - actually I just didn't care
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);
181 platform->RunShellCommand(command.GetData(),
191 PlatformPOSIX::PutFile (const lldb_private::FileSpec& source,
192 const lldb_private::FileSpec& destination,
196 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
200 if (FileSpec::Equal(source, destination, true))
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());
213 RunShellCommand(command.GetData(),
220 return Error("unable to perform copy");
221 if (uid == UINT32_MAX && gid == UINT32_MAX)
223 if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
224 return Error("unable to perform chown");
227 else if (m_remote_platform_sp)
229 if (GetSupportsRSync())
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())
240 if (!GetRSyncPrefix())
241 command.Printf("rsync %s %s %s",
246 command.Printf("rsync %s %s %s%s",
253 command.Printf("rsync %s %s %s:%s",
259 log->Printf("[PutFile] Running command: %s\n", command.GetData());
261 Host::RunShellCommand(command.GetData(),
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");
274 // if we are still here rsync has failed - let's try the slow way before giving up
278 log->Printf ("PlatformPOSIX::PutFile(src='%s', dst='%s', uid=%u, gid=%u)",
279 source.GetPath().c_str(),
280 destination.GetPath().c_str(),
282 gid); // REMOVE THIS PRINTF PRIOR TO CHECKIN
284 // read, write, read, write, ...
288 log->Printf("[PutFile] Using block by block transfer....\n");
290 uint32_t source_open_options = File::eOpenOptionRead;
291 if (source.GetFileType() == FileSpec::eFileTypeSymbolicLink)
292 source_open_options |= File::eOpenoptionDontFollowSymlinks;
294 File source_file(source, source_open_options, lldb::eFilePermissionsUserRW);
296 uint32_t permissions = source_file.GetPermissions(error);
297 if (permissions == 0)
298 permissions = lldb::eFilePermissionsFileDefault;
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,
307 log->Printf ("dest_file = %" PRIu64 "\n", dest_file);
310 if (dest_file == UINT64_MAX)
311 return Error("unable to open target file");
312 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
314 while (error.Success())
316 size_t bytes_read = buffer_sp->GetByteSize();
317 error = source_file.Read(buffer_sp->GetBytes(), bytes_read);
320 WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error);
321 offset += bytes_read;
326 CloseFile(dest_file, error);
327 if (uid == UINT32_MAX && gid == UINT32_MAX)
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");
335 return Platform::PutFile(source,destination,uid,gid);
339 PlatformPOSIX::GetFileSize (const FileSpec& file_spec)
342 return Host::GetFileSize(file_spec);
343 else if (m_remote_platform_sp)
344 return m_remote_platform_sp->GetFileSize(file_spec);
346 return Platform::GetFileSize(file_spec);
350 PlatformPOSIX::CreateSymlink(const char *src, const char *dst)
353 return Host::Symlink(src, dst);
354 else if (m_remote_platform_sp)
355 return m_remote_platform_sp->CreateSymlink(src, dst);
357 return Platform::CreateSymlink(src, dst);
361 PlatformPOSIX::GetFileExists (const FileSpec& file_spec)
364 return file_spec.Exists();
365 else if (m_remote_platform_sp)
366 return m_remote_platform_sp->GetFileExists(file_spec);
368 return Platform::GetFileExists(file_spec);
372 PlatformPOSIX::Unlink (const char *path)
375 return Host::Unlink (path);
376 else if (m_remote_platform_sp)
377 return m_remote_platform_sp->Unlink(path);
379 return Platform::Unlink(path);
383 PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path */,
384 const lldb_private::FileSpec& destination /* local file path */)
386 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
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");
397 if (FileSpec::Equal(source, destination, true))
398 return Error("local scenario->source and destination are the same file path: no operation performed");
400 StreamString cp_command;
401 cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
403 RunShellCommand(cp_command.GetData(),
410 return Error("unable to perform copy");
413 else if (m_remote_platform_sp)
415 if (GetSupportsRSync())
417 StreamString command;
418 if (GetIgnoresRemoteHostname())
420 if (!GetRSyncPrefix())
421 command.Printf("rsync %s %s %s",
426 command.Printf("rsync %s %s%s %s",
433 command.Printf("rsync %s %s:%s %s",
435 m_remote_platform_sp->GetHostname(),
439 log->Printf("[GetFile] Running command: %s\n", command.GetData());
441 Host::RunShellCommand(command.GetData(),
449 // If we are here, rsync has failed - let's try the slow way before giving up
452 // read/write, read/write, read/write, ...
456 log->Printf("[GetFile] Using block by block transfer....\n");
458 user_id_t fd_src = OpenFile (source,
459 File::eOpenOptionRead,
460 lldb::eFilePermissionsFileDefault,
463 if (fd_src == UINT64_MAX)
464 return Error("unable to open source file");
466 uint32_t permissions = 0;
467 error = GetFilePermissions(source.GetPath().c_str(), permissions);
469 if (permissions == 0)
470 permissions = lldb::eFilePermissionsFileDefault;
472 user_id_t fd_dst = Host::OpenFile(destination,
473 File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate,
477 if (fd_dst == UINT64_MAX)
480 error.SetErrorString("unable to open destination file");
485 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
488 while (error.Success())
490 const uint64_t n_read = ReadFile (fd_src,
492 buffer_sp->GetBytes(),
493 buffer_sp->GetByteSize(),
499 if (Host::WriteFile(fd_dst,
501 buffer_sp->GetBytes(),
506 error.SetErrorString("unable to write to destination file");
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))
519 error.SetErrorString("unable to close destination file");
524 return Platform::GetFile(source,destination);
528 PlatformPOSIX::GetPlatformSpecificConnectionInformation()
531 if (GetSupportsRSync())
533 stream.PutCString("rsync");
534 if ( (GetRSyncOpts() && *GetRSyncOpts()) ||
535 (GetRSyncPrefix() && *GetRSyncPrefix()) ||
536 GetIgnoresRemoteHostname())
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 ");
548 if (GetSupportsSSH())
550 stream.PutCString("ssh");
551 if (GetSSHOpts() && *GetSSHOpts())
552 stream.Printf(", options: '%s' ",GetSSHOpts());
554 if (GetLocalCacheDirectory() && *GetLocalCacheDirectory())
555 stream.Printf("cache dir: %s",GetLocalCacheDirectory());
556 if (stream.GetSize())
557 return stream.GetData();
563 PlatformPOSIX::CalculateMD5 (const FileSpec& file_spec,
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);
574 lldb_private::ConstString
575 PlatformPOSIX::GetRemoteWorkingDirectory()
577 if (IsRemote() && m_remote_platform_sp)
578 return m_remote_platform_sp->GetRemoteWorkingDirectory();
580 return Platform::GetRemoteWorkingDirectory();
584 PlatformPOSIX::SetRemoteWorkingDirectory(const lldb_private::ConstString &path)
586 if (IsRemote() && m_remote_platform_sp)
587 return m_remote_platform_sp->SetRemoteWorkingDirectory(path);
589 return Platform::SetRemoteWorkingDirectory(path);
593 PlatformPOSIX::CalculateTrapHandlerSymbolNames ()
595 m_trap_handlers.push_back (ConstString ("_sigtramp"));