1use std::fs::File;
2use std::io::prelude::*;
3use std::io::BufReader;
4use std::io::SeekFrom;
5use std::path::Path;
6use std::time::SystemTime;
7
8use super::client::*;
9use super::sync::*;
10use crate::result::*;
11
12pub trait AdbPush {
13 fn push_reader<R: Read + Seek>(&mut self, r: R, remote_path: &str) -> AdbResult<()>;
14 fn push<P: AsRef<Path>>(&mut self, local_path: P, remote_path: &str) -> AdbResult<()>;
15}
16
17impl AdbPush for AdbConnection {
18 fn push_reader<R: Read + Seek>(&mut self, r: R, remote_path: &str) -> AdbResult<()> {
19 let mut r = r;
20
21 let size = r.seek(SeekFrom::End(0))?;
22 r.seek(SeekFrom::Start(0))?;
23
24 debug!("size = 0x{:x}", size);
25
26 let stream = self.open_stream("sync:")?;
27
28 debug!("STAT");
29 let stat = SyncCommand::new_stat(remote_path);
30 let packet = AdbStreamPacket::new_write(stat);
31 stream.send(packet)?;
32 stream.sync_recv_ok()?;
33 debug!("STAT ok");
34
35 let reply = stream.sync_recv_command(Command::A_WRTE)?;
36 debug!(
37 "STAT data received: payload len = 0x{:x}",
38 reply.payload.len()
39 );
40
41 stream.send_ok()?;
42
43 debug!("SEND");
44 let send = SyncCommand::new_send(remote_path, 0o100644);
45 let packet = AdbStreamPacket::new_write(send);
46 stream.send(packet)?;
47 stream.sync_recv_ok()?;
48 debug!("SEND ok");
49
50 let mut data = SyncCommand::new_data(self.max_data_len());
51 let mut bytes_sent = 0;
52
53 loop {
54 let n = data.read_payload_from(&mut r)?;
55 if n == 0 {
56 break;
57 }
58
59 let next_pos: u64 = bytes_sent + n as u64;
60
61 assert!(next_pos <= size);
62
63 let is_last_chunk = next_pos == size;
64 debug!("DATA [0x{:x}:0x{:x}]", bytes_sent, next_pos);
65 bytes_sent = bytes_sent + n as u64;
66
67 let packet = AdbStreamPacket::new_write(&data);
68
69 if is_last_chunk {
70 let now = SystemTime::now()
71 .duration_since(SystemTime::UNIX_EPOCH)
72 .unwrap()
73 .as_secs() as u32;
74 let done = SyncCommand::new_done(now);
75 let space = self.max_data_len() - data.len();
76 if space >= done.len() {
77 data.extend(done);
78 let packet = AdbStreamPacket::new_write(&data);
79 stream.send(packet)?;
80 stream.sync_recv_ok()?;
81 debug!("DATA last chunk ok");
82 } else {
83 let append_len = space;
84 if append_len > 0 {
85 data.extend(&done[0..append_len]);
86 }
87 let packet = AdbStreamPacket::new_write(&data);
88 stream.send(packet)?;
89 stream.sync_recv_ok()?;
90 stream.send(AdbStreamPacket::new_write(&done[append_len..]))?;
91 stream.sync_recv_ok()?;
92 }
93 break;
94 } else {
95 stream.send(packet)?;
96
97 stream.sync_recv_ok()?;
98 debug!("DATA chunk ok");
99 }
100 }
101
102 assert_eq!(bytes_sent as u64, size);
103
104 let reply = stream.sync_recv_command(Command::A_WRTE)?;
105 debug!("result = {}", String::from_utf8_lossy(&reply.payload));
106
107 stream.send_ok()?;
108
109 debug!("QUIT");
110 let quit = SyncCommand::new_quit();
111 let packet = AdbStreamPacket::new_write(quit);
112 stream.send(packet)?;
113
114 stream.sync_recv_ok()?;
115
116 stream.send_close()?;
117
118 stream.sync_recv_command(Command::A_CLSE)?;
119
120 Ok(())
121 }
122
123 fn push<P: AsRef<Path>>(&mut self, local_path: P, remote_path: &str) -> AdbResult<()> {
124 let file = File::open(local_path)?;
125 let r = BufReader::new(file);
126 self.push_reader(r, remote_path)
127 }
128}