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