/// <summary> /// Push a single file /// </summary> /// <param name="local">the local file to push</param> /// <param name="remotePath">the remote file (length max is 1024)</param> /// <param name="monitor">the monitor. The monitor must be started already.</param> /// <returns>a SyncResult object with a code and an optional message.</returns> /// <exception cref="ArgumentNullException">Throws if monitor is null</exception> private SyncResult DoPushFile(string local, string remotePath, ISyncProgressMonitor monitor) { if (monitor == null) { throw new ArgumentNullException("monitor", "Monitor cannot be null"); } Log.I(TAG, "Pushing file '" + local + "' to '" + Device + remotePath + "'."); byte[] msg; int timeOut = DdmPreferences.Timeout; FileStream fs; try { byte[] remotePathContent = StringHelper.GetBytes(remotePath, AdbHelper.DEFAULT_ENCODING); if (remotePathContent.Length > REMOTE_PATH_MAX_LENGTH) { return(new SyncResult(ErrorCodeHelper.RESULT_REMOTE_PATH_LENGTH)); } // this shouldn't happen but still... if (!File.Exists(local)) { return(new SyncResult(ErrorCodeHelper.RESULT_NO_LOCAL_FILE)); } // create the stream to read the file fs = new FileStream(local, System.IO.FileMode.Open, FileAccess.Read); // create the header for the action msg = CreateSendFileRequest(StringHelper.GetBytes(SEND), remotePathContent, (FileMode)0644); } catch (EncoderFallbackException e) { Log.E(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_REMOTE_PATH_ENCODING, e)); } catch (FileNotFoundException e) { Log.E(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_FILE_READ_ERROR, e)); } // and send it. We use a custom try/catch block to make the difference between // file and network IO exceptions. try { AdbHelper.Instance.Write(Channel, msg, -1, timeOut); } catch (IOException e) { Log.E(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR, e)); } // create the buffer used to read. // we read max SYNC_DATA_MAX, but we need 2 4 bytes at the beginning. if (DataBuffer == null) { DataBuffer = new byte[SYNC_DATA_MAX + 8]; } byte[] bDATA = StringHelper.GetBytes(DATA); Array.Copy(bDATA, 0, DataBuffer, 0, bDATA.Length); // look while there is something to read while (true) { // check if we're canceled if (monitor.IsCanceled) { return(new SyncResult(ErrorCodeHelper.RESULT_CANCELED)); } // read up to SYNC_DATA_MAX int readCount; try { readCount = fs.Read(DataBuffer, 8, SYNC_DATA_MAX); } catch (IOException e) { return(new SyncResult(ErrorCodeHelper.RESULT_FILE_READ_ERROR, e)); } if (readCount == 0) { // we reached the end of the file break; } // now send the data to the device // first write the amount read ArrayHelper.Swap32bitsToArray(readCount, DataBuffer, 4); // now write it try { AdbHelper.Instance.Write(Channel, DataBuffer, readCount + 8, timeOut); } catch (IOException e) { return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR, e)); } // and advance the monitor monitor.Advance(readCount); } // close the local file try { fs.Close(); fs.Dispose(); } catch (IOException e) { Log.E(TAG, e); } try { // create the DONE message long time = DateTimeHelper.CurrentTimeMillis(DateTime.Now) / 1000; msg = CreateRequest(DONE, (int)time); // and send it. AdbHelper.Instance.Write(Channel, msg, -1, timeOut); // read the result, in a byte array containing 2 ints // (id, size) byte[] result = new byte[8]; AdbHelper.Instance.Read(Channel, result, -1 /* full length */); if (!CheckResult(result, StringHelper.GetBytes(OKAY))) { if (CheckResult(result, StringHelper.GetBytes(FAIL))) { // read some error message... int len = ArrayHelper.Swap32bitFromArray(result, 4); AdbHelper.Instance.Read(Channel, DataBuffer, len); // output the result? string message = StringHelper.GetString(DataBuffer, 0, len); Log.E(TAG, "transfer error: " + message); return(new SyncResult(ErrorCodeHelper.RESULT_UNKNOWN_ERROR, message)); } return(new SyncResult(ErrorCodeHelper.RESULT_UNKNOWN_ERROR)); } } catch (IOException e) { return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR, e)); } // files pushed have no permissions... this.Device.FileSystem.Chmod(remotePath, "0666"); return(new SyncResult(ErrorCodeHelper.RESULT_OK)); }
/// <summary> /// Pulls a remote file /// </summary> /// <param name="remotePath">the remote file (length max is 1024)</param> /// <param name="localPath">the local destination</param> /// <param name="monitor">the monitor. The monitor must be started already.</param> /// <returns>a SyncResult object with a code and an optional message.</returns> /// <exception cref="ArgumentNullException">Throws if monitor is null</exception> private SyncResult DoPullFile(string remotePath, string localPath, ISyncProgressMonitor monitor) { if (monitor == null) { throw new ArgumentNullException("monitor", "Monitor cannot be null"); } Log.I(TAG, "Pulling file '" + localPath + "' from '" + Device + remotePath + "'."); byte[] pullResult = new byte[8]; int timeOut = DdmPreferences.Timeout; try { byte[] remotePathContent = StringHelper.GetBytes(remotePath, AdbHelper.DEFAULT_ENCODING); if (remotePathContent.Length > REMOTE_PATH_MAX_LENGTH) { return(new SyncResult(ErrorCodeHelper.RESULT_REMOTE_PATH_LENGTH)); } // create the full request message byte[] msg = CreateFileRequest(StringHelper.GetBytes(RECV), remotePathContent); // and send it. AdbHelper.Instance.Write(Channel, msg, -1, timeOut); // read the result, in a byte array containing 2 ints // (id, size) AdbHelper.Instance.Read(Channel, pullResult, -1); // check we have the proper data back if (CheckResult(pullResult, StringHelper.GetBytes(DATA)) == false && CheckResult(pullResult, StringHelper.GetBytes(DONE)) == false) { return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR)); } } catch (EncoderFallbackException e) { Log.E(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_REMOTE_PATH_ENCODING, e)); } catch (IOException e) { Log.E(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR, e)); } // access the destination file FileInfo f = new FileInfo(localPath); // create the stream to write in the file. We use a new try/catch block to differentiate // between file and network io exceptions. FileStream fos; try { fos = new FileStream(f.FullName, System.IO.FileMode.Create, FileAccess.Write); } catch (FileNotFoundException e) { Log.E(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_FILE_WRITE_ERROR, e)); } // the buffer to read the data byte[] data = new byte[SYNC_DATA_MAX]; using (fos) { // loop to get data until we're done. while (true) { // check if we're cancelled if (monitor.IsCanceled) { return(new SyncResult(ErrorCodeHelper.RESULT_CANCELED)); } // if we're done, we stop the loop if (CheckResult(pullResult, StringHelper.GetBytes(DONE))) { break; } if (CheckResult(pullResult, StringHelper.GetBytes(DATA)) == false) { // hmm there's an error return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR)); } int length = ArrayHelper.Swap32bitFromArray(pullResult, 4); if (length > SYNC_DATA_MAX) { // buffer overrun! // error and exit return(new SyncResult(ErrorCodeHelper.RESULT_BUFFER_OVERRUN)); } try { // now read the length we received AdbHelper.Instance.Read(Channel, data, length); // get the header for the next packet. AdbHelper.Instance.Read(Channel, pullResult, -1); } catch (IOException e) { Log.E(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR, e)); } // write the content in the file try { fos.Write(data, 0, data.Length); } catch (IOException e) { Log.E(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_FILE_WRITE_ERROR, e)); } monitor.Advance(length); } try { fos.Flush(); } catch (IOException e) { Log.E(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_FILE_WRITE_ERROR, e)); } try { fos.Close(); fos.Dispose(); } catch (IOException e) { Log.E(TAG, e); } } return(new SyncResult(ErrorCodeHelper.RESULT_OK)); }
/// <summary> /// Executes a shell command on the remote device /// </summary> /// <param name="endPoint">The socket end point</param> /// <param name="command">The command to execute</param> /// <param name="device">The device to execute on</param> /// <param name="rcvr">The shell output receiver</param> /// <exception cref="FileNotFoundException">Throws if the result is 'command': not found</exception> /// <exception cref="IOException">Throws if there is a problem reading / writing to the socket</exception> /// <exception cref="OperationCanceledException">Throws if the execution was canceled</exception> /// <exception cref="EndOfStreamException">Throws if the Socket.Receice ever returns -1</exception> public void ExecuteRemoteCommand(IPEndPoint endPoint, string command, Device device, IShellOutputReceiver rcvr) { Log.I(TAG, "executing '" + command + "' on '" + device + "'."); Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); if (!device.IsOnline) { return; } try { socket.ReceiveTimeout = SOCKET_TIMEOUT; socket.SendTimeout = SOCKET_TIMEOUT; socket.Connect(endPoint); socket.Blocking = true; SetDevice(socket, device); byte[] request = FormAdbRequest("shell:" + command); if (!Write(socket, request)) { throw new AdbException("failed submitting shell command"); } AdbResponse resp = ReadAdbResponse(socket, false /* readDiagstring */); if (!resp.IOSuccess || !resp.Okay) { throw new AdbException("sad result from adb: " + resp.Message); } byte[] data = new byte[16384]; int count = -1; socket.ReceiveTimeout = SOCKET_TIMEOUT_SHELLCOMMAND; while (count != 0) { if (rcvr != null && rcvr.IsCancelled) { Log.W(TAG, "execute: cancelled"); throw new OperationCanceledException(); } count = socket.Receive(data); if (count < 0) { // we're at the end, we flush the output rcvr.Flush(); Log.W(TAG, "execute '" + command + "' on '" + device + "' : EOF hit. Read: " + count); throw new EndOfStreamException(); } else if (count == 0) { // do nothing } else { string[] cmd = command.Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); string sdata = StringHelper.GetString(data, 0, count, AdbHelper.DEFAULT_ENCODING); var sdataTrimmed = sdata.Trim(); if (sdataTrimmed.EndsWith(string.Format("{0}: not found", cmd[0]))) { Log.W("AdbHelper", "The remote execution returned: '{0}: not found'", cmd[0]); throw new FileNotFoundException(string.Format("The remote execution returned: '{0}: not found'", cmd[0])); } if (sdataTrimmed.EndsWith("No such file or directory")) { Log.W("AdbHelper", "The remote execution returned: {0}", sdataTrimmed); throw new FileNotFoundException(string.Format("The remote execution returned: {0}", sdataTrimmed)); } // for busybox applets // cmd: applet not found if (cmd.Length > 1 && sdataTrimmed.EndsWith(string.Format("{0}: applet not found", cmd[1]))) { Log.W("AdbHelper", "The remote execution returned: '{0}'", sdataTrimmed); throw new FileNotFoundException(string.Format("The remote execution returned: '{0}'", sdataTrimmed)); } // checks if the permission to execute the command was denied. // workitem: 16822 if (sdataTrimmed.EndsWith(string.Format("{0}: permission denied", cmd[0])) || sdataTrimmed.EndsWith(string.Format("{0}: access denied", cmd[0]))) { Log.W("AdbHelper", "The remote execution returned: '{0}'", sdataTrimmed); throw new PermissionDeniedException(string.Format("The remote execution returned: '{0}'", sdataTrimmed)); } // Add the data to the receiver if (rcvr != null) { rcvr.AddOutput(data, 0, count); } } } } /*catch ( Exception e ) { * Log.e ( "AdbHelper", e ); * throw; * }*/ finally { if (socket != null) { socket.Close(); } rcvr.Flush(); } }