Mercurial > 510Connectbot
comparison src/ch/ethz/ssh2/SCPClient.java @ 273:91a31873c42a ganymed
start conversion from trilead to ganymed
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Fri, 18 Jul 2014 11:21:46 -0700 |
parents | |
children | 9ae4ed7bb523 |
comparison
equal
deleted
inserted
replaced
272:ce2f4e397703 | 273:91a31873c42a |
---|---|
1 package ch.ethz.ssh2; | |
2 | |
3 import java.io.IOException; | |
4 import java.io.InputStream; | |
5 import java.nio.charset.Charset; | |
6 import java.nio.charset.UnsupportedCharsetException; | |
7 | |
8 /** | |
9 * A very basic <code>SCPClient</code> that can be used to copy files from/to | |
10 * the SSH-2 server. On the server side, the "scp" program must be in the PATH. | |
11 * <p/> | |
12 * This scp client is thread safe - you can download (and upload) different sets | |
13 * of files concurrently without any troubles. The <code>SCPClient</code> is | |
14 * actually mapping every request to a distinct {@link ch.ethz.ssh2.Session}. | |
15 * | |
16 * @author Christian Plattner, plattner@inf.ethz.ch | |
17 * @version $Id: SCPClient.java 85 2014-04-07 14:05:09Z dkocher@sudo.ch $ | |
18 */ | |
19 | |
20 public class SCPClient | |
21 { | |
22 Connection conn; | |
23 | |
24 String charsetName = null; | |
25 | |
26 /** | |
27 * Set the charset used to convert between Java Unicode Strings and byte encodings | |
28 * used by the server for paths and file names. | |
29 * | |
30 * @param charset the name of the charset to be used or <code>null</code> to use the platform's | |
31 * default encoding. | |
32 * @throws IOException | |
33 * @see #getCharset() | |
34 */ | |
35 public void setCharset(String charset) throws IOException | |
36 { | |
37 if (charset == null) | |
38 { | |
39 charsetName = charset; | |
40 return; | |
41 } | |
42 | |
43 try | |
44 { | |
45 Charset.forName(charset); | |
46 } | |
47 catch (UnsupportedCharsetException e) | |
48 { | |
49 throw new IOException("This charset is not supported", e); | |
50 } | |
51 charsetName = charset; | |
52 } | |
53 | |
54 /** | |
55 * The currently used charset for filename encoding/decoding. | |
56 * | |
57 * @return The name of the charset (<code>null</code> if the platform's default charset is being used) | |
58 * @see #setCharset(String) | |
59 */ | |
60 public String getCharset() | |
61 { | |
62 return charsetName; | |
63 } | |
64 | |
65 public class LenNamePair | |
66 { | |
67 public long length; | |
68 String filename; | |
69 } | |
70 | |
71 public SCPClient(Connection conn) | |
72 { | |
73 if (conn == null) | |
74 throw new IllegalArgumentException("Cannot accept null argument!"); | |
75 this.conn = conn; | |
76 } | |
77 | |
78 protected void readResponse(InputStream is) throws IOException | |
79 { | |
80 int c = is.read(); | |
81 | |
82 if (c == 0) | |
83 return; | |
84 | |
85 if (c == -1) | |
86 throw new IOException("Remote scp terminated unexpectedly."); | |
87 | |
88 if ((c != 1) && (c != 2)) | |
89 throw new IOException("Remote scp sent illegal error code."); | |
90 | |
91 if (c == 2) | |
92 throw new IOException("Remote scp terminated with error."); | |
93 | |
94 String err = receiveLine(is); | |
95 throw new IOException("Remote scp terminated with error (" + err + ")."); | |
96 } | |
97 | |
98 protected String receiveLine(InputStream is) throws IOException | |
99 { | |
100 StringBuilder sb = new StringBuilder(30); | |
101 | |
102 while (true) | |
103 { | |
104 /* This is a random limit - if your path names are longer, then adjust it */ | |
105 | |
106 if (sb.length() > 8192) | |
107 throw new IOException("Remote scp sent a too long line"); | |
108 | |
109 int c = is.read(); | |
110 | |
111 if (c < 0) | |
112 throw new IOException("Remote scp terminated unexpectedly."); | |
113 | |
114 if (c == '\n') | |
115 break; | |
116 | |
117 sb.append((char) c); | |
118 | |
119 } | |
120 return sb.toString(); | |
121 } | |
122 | |
123 protected LenNamePair parseCLine(String line) throws IOException | |
124 { | |
125 /* Minimum line: "xxxx y z" ---> 8 chars */ | |
126 | |
127 if (line.length() < 8) | |
128 throw new IOException("Malformed C line sent by remote SCP binary, line too short."); | |
129 | |
130 if ((line.charAt(4) != ' ') || (line.charAt(5) == ' ')) | |
131 throw new IOException("Malformed C line sent by remote SCP binary."); | |
132 | |
133 int length_name_sep = line.indexOf(' ', 5); | |
134 | |
135 if (length_name_sep == -1) | |
136 throw new IOException("Malformed C line sent by remote SCP binary."); | |
137 | |
138 String length_substring = line.substring(5, length_name_sep); | |
139 String name_substring = line.substring(length_name_sep + 1); | |
140 | |
141 if ((length_substring.length() <= 0) || (name_substring.length() <= 0)) | |
142 throw new IOException("Malformed C line sent by remote SCP binary."); | |
143 | |
144 if ((6 + length_substring.length() + name_substring.length()) != line.length()) | |
145 throw new IOException("Malformed C line sent by remote SCP binary."); | |
146 | |
147 final long len; | |
148 try | |
149 { | |
150 len = Long.parseLong(length_substring); | |
151 } | |
152 catch (NumberFormatException e) | |
153 { | |
154 throw new IOException("Malformed C line sent by remote SCP binary, cannot parse file length."); | |
155 } | |
156 | |
157 if (len < 0) | |
158 throw new IOException("Malformed C line sent by remote SCP binary, illegal file length."); | |
159 | |
160 LenNamePair lnp = new LenNamePair(); | |
161 lnp.length = len; | |
162 lnp.filename = name_substring; | |
163 | |
164 return lnp; | |
165 } | |
166 | |
167 /** | |
168 * The session for opened for this SCP transfer must be closed using | |
169 * SCPOutputStream#close | |
170 * | |
171 * @param remoteFile | |
172 * @param length The size of the file to send | |
173 * @param remoteTargetDirectory | |
174 * @param mode | |
175 * @return | |
176 * @throws IOException | |
177 */ | |
178 public SCPOutputStream put(final String remoteFile, long length, String remoteTargetDirectory, String mode) | |
179 throws IOException | |
180 { | |
181 Session sess = null; | |
182 | |
183 if (null == remoteFile) | |
184 throw new IllegalArgumentException("Null argument."); | |
185 if (null == remoteTargetDirectory) | |
186 remoteTargetDirectory = ""; | |
187 if (null == mode) | |
188 mode = "0600"; | |
189 if (mode.length() != 4) | |
190 throw new IllegalArgumentException("Invalid mode."); | |
191 | |
192 for (int i = 0; i < mode.length(); i++) | |
193 if (Character.isDigit(mode.charAt(i)) == false) | |
194 throw new IllegalArgumentException("Invalid mode."); | |
195 | |
196 remoteTargetDirectory = (remoteTargetDirectory.length() > 0) ? remoteTargetDirectory : "."; | |
197 | |
198 String cmd = "scp -t -d \"" + remoteTargetDirectory + "\""; | |
199 | |
200 sess = conn.openSession(); | |
201 sess.execCommand(cmd, charsetName); | |
202 | |
203 return new SCPOutputStream(this, sess, remoteFile, length, mode); | |
204 } | |
205 | |
206 /** | |
207 * The session for opened for this SCP transfer must be closed using | |
208 * SCPInputStream#close | |
209 * | |
210 * @param remoteFile | |
211 * @return | |
212 * @throws IOException | |
213 */ | |
214 public SCPInputStream get(final String remoteFile) throws IOException | |
215 { | |
216 Session sess = null; | |
217 | |
218 if (null == remoteFile) | |
219 throw new IllegalArgumentException("Null argument."); | |
220 | |
221 if (remoteFile.length() == 0) | |
222 throw new IllegalArgumentException("Cannot accept empty filename."); | |
223 | |
224 String cmd = "scp -f"; | |
225 cmd += (" \"" + remoteFile + "\""); | |
226 | |
227 sess = conn.openSession(); | |
228 sess.execCommand(cmd, charsetName); | |
229 | |
230 return new SCPInputStream(this, sess); | |
231 } | |
232 } |