Author: hadrian
Date: Fri Apr 6 03:17:01 2012
New Revision: 1310155
URL: http://svn.apache.org/viewvc?rev=1310155&view=rev
Log:
CAMEL-5020. Add test for file permissions
Modified:
camel/trunk/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpConfiguration.java
camel/trunk/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpOperations.java
camel/trunk/components/camel-jsch/src/test/java/org/apache/camel/component/jsch/ScpSimpleProduceTest.java
Modified:
camel/trunk/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpConfiguration.java
URL:
http://svn.apache.org/viewvc/camel/trunk/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpConfiguration.java?rev=1310155&r1=1310154&r2=1310155&view=diff
==============================================================================
---
camel/trunk/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpConfiguration.java
(original)
+++
camel/trunk/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpConfiguration.java
Fri Apr 6 03:17:01 2012
@@ -26,6 +26,7 @@ import org.apache.camel.component.file.r
public class ScpConfiguration extends RemoteFileConfiguration {
public static final int DEFAULT_SFTP_PORT = 22;
+ public static final String DEFAULT_MOD = "664";
private String knownHostsFile;
private String privateKeyFile;
private String privateKeyFilePassphrase;
@@ -100,6 +101,17 @@ public class ScpConfiguration extends Re
}
public void setChmod(String chmod) {
+ if (chmod.length() == 3) {
+ for (byte c : chmod.getBytes()) {
+ if (c < '0' || c > '7') {
+ chmod = DEFAULT_MOD;
+ break;
+ }
+ }
+ } else {
+ chmod = DEFAULT_MOD;
+ }
+ // May be interesting to log the fallback to DEFAULT_MOD for invalid
configuration
this.chmod = chmod;
}
Modified:
camel/trunk/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpOperations.java
URL:
http://svn.apache.org/viewvc/camel/trunk/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpOperations.java?rev=1310155&r1=1310154&r2=1310155&view=diff
==============================================================================
---
camel/trunk/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpOperations.java
(original)
+++
camel/trunk/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpOperations.java
Fri Apr 6 03:17:01 2012
@@ -17,6 +17,8 @@
package org.apache.camel.component.jsch;
import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -103,7 +105,7 @@ public class ScpOperations implements Re
LOG.trace("Channel connected to {}",
cfg.remoteServerInformation());
try {
- write(channel, file,
ExchangeHelper.getMandatoryInBody(exchange, InputStream.class));
+ write(channel, file,
ExchangeHelper.getMandatoryInBody(exchange, InputStream.class), cfg);
} catch (InvalidPayloadException e) {
throw new GenericFileOperationFailedException("Failed extract
message body as InputStream", e);
} catch (IOException e) {
@@ -220,60 +222,115 @@ public class ScpOperations implements Re
return session;
}
- private void write(ChannelExec c, String name, InputStream data) throws
IOException {
+ private void write(ChannelExec c, String name, InputStream data,
ScpConfiguration cfg) throws IOException {
OutputStream os = c.getOutputStream();
InputStream is = c.getInputStream();
- writeFile(name, data, os, is);
+ writeFile(name, data, os, is, cfg);
os.close();
is.close();
}
- private void writeFile(String filename, InputStream data, OutputStream os,
InputStream is) throws IOException {
+ private void writeFile(String filename, InputStream data, OutputStream os,
InputStream is, ScpConfiguration cfg) throws IOException {
+ final int lineFeed = '\n';
+ String bytes;
int pos = filename.indexOf('/');
if (pos >= 0) {
// write to child directory
String dir = filename.substring(0, pos);
- os.write(("D0775 0 " + dir + "\n").getBytes());
+ bytes = "D0775 0 " + dir;
+ LOG.trace("[scp:sink] {}", bytes);
+ os.write(bytes.getBytes());
+ os.write(lineFeed);
os.flush();
- is.read();
+ readAck(is, false);
- writeFile(filename.substring(pos + 1), data, os, is);
+ writeFile(filename.substring(pos + 1), data, os, is, cfg);
- os.write("E\n".getBytes());
+ bytes = "E";
+ LOG.trace("[scp:sink] {}", bytes);
+ os.write(bytes.getBytes());
+ os.write(lineFeed);
os.flush();
- is.read();
+ readAck(is, false);
} else {
int count = 0;
int read = 0;
int size = endpoint.getBufferSize();
- byte[] bytes = new byte[size];
+ byte[] reply = new byte[size];
// figure out the stream size as we need to pass it in the header
BufferedInputStream buffer = new BufferedInputStream(data, size);
buffer.mark(Integer.MAX_VALUE);
- while ((read = buffer.read(bytes)) != -1) {
+ while ((read = buffer.read(reply)) != -1) {
count += read;
}
// send the header
- os.write(("C0775 " + count + " " + filename + "\n").getBytes());
+ bytes = "C0" + cfg.getChmod() + " " + count + " " + filename;
+ LOG.trace("[scp:sink] {}", bytes);
+ os.write(bytes.getBytes());
+ os.write(lineFeed);
os.flush();
- is.read();
+ readAck(is, false);
// now send the stream
buffer.reset();
- while ((read = buffer.read(bytes)) != -1) {
- os.write(bytes, 0, read);
+ while ((read = buffer.read(reply)) != -1) {
+ os.write(reply, 0, read);
}
- os.flush();
- is.read();
+ writeAck(os);
+ readAck(is, false);
}
+ }
+
+ private void writeAck(OutputStream os) throws IOException {
os.write(0);
os.flush();
}
+
+ private int readAck(InputStream is, boolean failOnEof) throws IOException {
+ String message;
+ int answer = is.read();
+ switch (answer) {
+ case -1:
+ if (failOnEof) {
+ message = "[scp] Unexpected end of stream";
+ LOG.info(message);
+ throw new EOFException(message);
+ }
+ break;
+ case 1:
+ message = "[scp] WARN " + readLine(is);
+ LOG.info(message);
+ break;
+ case 2:
+ message = "[scp] NACK " + readLine(is);
+ LOG.info(message);
+ throw new IOException(message);
+ default:
+ // case 0:
+ break;
+ }
+ return answer;
+ }
+ private String readLine(InputStream is) throws IOException {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ int c = 0;
+ do {
+ c = is.read();
+ if (c == '\n') {
+ return bytes.toString();
+ }
+ bytes.write(c);
+ } while (c != -1);
+ String message = "[scp] Unexpected end of stream";
+ LOG.info(message);
+ throw new IOException(message);
+ }
+
private static String getRemoteTarget(ScpConfiguration config) {
// use current dir (".") if target directory not specified in uri
return config.getDirectory().isEmpty() ? "." : config.getDirectory();
Modified:
camel/trunk/components/camel-jsch/src/test/java/org/apache/camel/component/jsch/ScpSimpleProduceTest.java
URL:
http://svn.apache.org/viewvc/camel/trunk/components/camel-jsch/src/test/java/org/apache/camel/component/jsch/ScpSimpleProduceTest.java?rev=1310155&r1=1310154&r2=1310155&view=diff
==============================================================================
---
camel/trunk/components/camel-jsch/src/test/java/org/apache/camel/component/jsch/ScpSimpleProduceTest.java
(original)
+++
camel/trunk/components/camel-jsch/src/test/java/org/apache/camel/component/jsch/ScpSimpleProduceTest.java
Fri Apr 6 03:17:01 2012
@@ -66,4 +66,18 @@ public class ScpSimpleProduceTest extend
assertTrue("File should exist: " + file, file.exists());
assertEquals("Farewell World",
context.getTypeConverter().convertTo(String.class, file));
}
+
+ @Test
+ public void testScpProduceChmod() throws Exception {
+ Assume.assumeTrue(this.isSetupComplete());
+
+ String uri = getScpUri() +
"?username=admin&password=admin&chmod=640&knownHostsFile=" +
getKnownHostsFile();
+ template.sendBodyAndHeader(uri, "Bonjour Monde", Exchange.FILE_NAME,
"monde.txt");
+
+ File file = new File(getScpPath() + "/monde.txt").getAbsoluteFile();
+ assertTrue("File should exist: " + file, file.exists());
+ // Mina sshd we use for testing ignores file perms;
+ // assertFalse("File should not have execute rights: " + file,
file.canExecute());
+ assertEquals("Bonjour Monde",
context.getTypeConverter().convertTo(String.class, file));
+ }
}