https://bz.apache.org/bugzilla/show_bug.cgi?id=43271 Apparently the remote umask still comes into play and the result won't be exactly what we intended it to be. Based on patch by Holly Cumminsmaster
| @@ -126,6 +126,10 @@ Other changes: | |||||
| https://issues.apache.org/jira/browse/COMPRESS-314 | https://issues.apache.org/jira/browse/COMPRESS-314 | ||||
| https://issues.apache.org/jira/browse/COMPRESS-315 | https://issues.apache.org/jira/browse/COMPRESS-315 | ||||
| * <scp> has new attributes fileMode and dirMode that control the | |||||
| permissions on the remote side when sending data via SSH. | |||||
| Bugzilla Report 43271 | |||||
| Changes from Ant 1.9.3 TO Ant 1.9.4 | Changes from Ant 1.9.3 TO Ant 1.9.4 | ||||
| =================================== | =================================== | ||||
| @@ -182,6 +182,24 @@ for more information. This task has been tested with jsch-0.1.2 and later.</p> | |||||
| 1.8.0</em></td> | 1.8.0</em></td> | ||||
| <td valign="top" align="center">No; defaults to false.</td> | <td valign="top" align="center">No; defaults to false.</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td valign="top">filemode</td> | |||||
| <td valign="top">A 3 digit octal string, specify the user, group | |||||
| and other modes in the standard Unix fashion. Only applies to | |||||
| uploaded files. Note the actual permissions of the remote | |||||
| file will be governed by this setting and the UMASK on the | |||||
| remote server. Default is 644. <em>since Ant 1.9.5</em>.</td> | |||||
| <td align="center" valign="top">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">dirmode</td> | |||||
| <td valign="top">A 3 digit octal string, specify the user, group | |||||
| and other modes in the standard Unix fashion. Only applies to | |||||
| uploaded dirs. Note the actual permissions of the remote | |||||
| dir will be governed by this setting and the UMASK on the | |||||
| remote server. Default is 644. <em>since Ant 1.9.5</em>.</td> | |||||
| <td align="center" valign="top">No</td> | |||||
| </tr> | |||||
| </table> | </table> | ||||
| <h3>Parameters specified as nested elements</h3> | <h3>Parameters specified as nested elements</h3> | ||||
| @@ -261,7 +279,7 @@ system (via the ps command). The best approach is to use the | |||||
| <p> | <p> | ||||
| <p><strong>Unix Note:</strong> File permissions are not retained when files | <p><strong>Unix Note:</strong> File permissions are not retained when files | ||||
| are copied; they end up with the default <code>UMASK</code> permissions | |||||
| are downloaded; they end up with the default <code>UMASK</code> permissions | |||||
| instead. This is caused by the lack of any means to query or set file | instead. This is caused by the lack of any means to query or set file | ||||
| permissions in the current Java runtimes. If you need a permission- | permissions in the current Java runtimes. If you need a permission- | ||||
| preserving copy function, use <code><exec executable="scp" ... ></code> | preserving copy function, use <code><exec executable="scp" ... ></code> | ||||
| @@ -52,6 +52,7 @@ public class Scp extends SSHBase { | |||||
| private List fileSets = null; | private List fileSets = null; | ||||
| private boolean isFromRemote, isToRemote; | private boolean isFromRemote, isToRemote; | ||||
| private boolean isSftp = false; | private boolean isSftp = false; | ||||
| private Integer fileMode, dirMode; | |||||
| /** | /** | ||||
| * Sets the file to be transferred. This can either be a remote | * Sets the file to be transferred. This can either be a remote | ||||
| @@ -180,6 +181,22 @@ public class Scp extends SSHBase { | |||||
| isSftp = yesOrNo; | isSftp = yesOrNo; | ||||
| } | } | ||||
| /** | |||||
| * Set the file mode, defaults to "644". | |||||
| * @since Ant 1.9.5 | |||||
| */ | |||||
| public void setFileMode(String fileMode) { | |||||
| this.fileMode = Integer.parseInt(fileMode, 8); | |||||
| } | |||||
| /** | |||||
| * Set the dir mode, defaults to "755". | |||||
| * @since Ant 1.9.5 | |||||
| */ | |||||
| public void setDirMode(String dirMode) { | |||||
| this.dirMode = Integer.parseInt(dirMode, 8); | |||||
| } | |||||
| /** | /** | ||||
| * Adds a FileSet transfer to remote host. NOTE: Either | * Adds a FileSet transfer to remote host. NOTE: Either | ||||
| * addFileSet() or setFile() are required. But, not both. | * addFileSet() or setFile() are required. But, not both. | ||||
| @@ -307,6 +324,12 @@ public class Scp extends SSHBase { | |||||
| list, file); | list, file); | ||||
| } | } | ||||
| message.setLogListener(this); | message.setLogListener(this); | ||||
| if (fileMode != null) { | |||||
| message.setFileMode(fileMode.intValue()); | |||||
| } | |||||
| if (dirMode != null) { | |||||
| message.setDirMode(dirMode.intValue()); | |||||
| } | |||||
| message.execute(); | message.execute(); | ||||
| } | } | ||||
| } finally { | } finally { | ||||
| @@ -335,6 +358,12 @@ public class Scp extends SSHBase { | |||||
| file); | file); | ||||
| } | } | ||||
| message.setLogListener(this); | message.setLogListener(this); | ||||
| if (fileMode != null) { | |||||
| message.setFileMode(fileMode.intValue()); | |||||
| } | |||||
| if (dirMode != null) { | |||||
| message.setDirMode(dirMode.intValue()); | |||||
| } | |||||
| message.execute(); | message.execute(); | ||||
| } finally { | } finally { | ||||
| if (session != null) { | if (session != null) { | ||||
| @@ -37,10 +37,13 @@ public class ScpToMessage extends AbstractSshMessage { | |||||
| private static final int HUNDRED_KILOBYTES = 102400; | private static final int HUNDRED_KILOBYTES = 102400; | ||||
| private static final int BUFFER_SIZE = 100*1024; | private static final int BUFFER_SIZE = 100*1024; | ||||
| private static final int DEFAULT_DIR_MODE = 0755; | |||||
| private static final int DEFAULT_FILE_MODE = 0644; | |||||
| private File localFile; | private File localFile; | ||||
| private String remotePath; | private String remotePath; | ||||
| private List directoryList; | private List directoryList; | ||||
| private Integer fileMode, dirMode; | |||||
| /** | /** | ||||
| * Constructor for ScpToMessage | * Constructor for ScpToMessage | ||||
| @@ -137,6 +140,7 @@ public class ScpToMessage extends AbstractSshMessage { | |||||
| * @throws IOException on i/o errors | * @throws IOException on i/o errors | ||||
| * @throws JSchException on errors detected by scp | * @throws JSchException on errors detected by scp | ||||
| */ | */ | ||||
| @Override | |||||
| public void execute() throws IOException, JSchException { | public void execute() throws IOException, JSchException { | ||||
| if (directoryList != null) { | if (directoryList != null) { | ||||
| doMultipleTransfer(); | doMultipleTransfer(); | ||||
| @@ -201,7 +205,9 @@ public class ScpToMessage extends AbstractSshMessage { | |||||
| private void sendDirectoryToRemote(final Directory directory, | private void sendDirectoryToRemote(final Directory directory, | ||||
| final InputStream in, | final InputStream in, | ||||
| final OutputStream out) throws IOException { | final OutputStream out) throws IOException { | ||||
| String command = "D0755 0 "; | |||||
| String command = "D0"; | |||||
| command += Integer.toOctalString(getDirMode()); | |||||
| command += " 0 "; | |||||
| command += directory.getDirectory().getName(); | command += directory.getDirectory().getName(); | ||||
| command += "\n"; | command += "\n"; | ||||
| @@ -220,7 +226,9 @@ public class ScpToMessage extends AbstractSshMessage { | |||||
| final OutputStream out) throws IOException { | final OutputStream out) throws IOException { | ||||
| // send "C0644 filesize filename", where filename should not include '/' | // send "C0644 filesize filename", where filename should not include '/' | ||||
| final long filesize = localFile.length(); | final long filesize = localFile.length(); | ||||
| String command = "C0644 " + filesize + " "; | |||||
| String command = "C0"; | |||||
| command += Integer.toOctalString(getFileMode()); | |||||
| command += " " + filesize + " "; | |||||
| command += localFile.getName(); | command += localFile.getName(); | ||||
| command += "\n"; | command += "\n"; | ||||
| @@ -287,4 +295,37 @@ public class ScpToMessage extends AbstractSshMessage { | |||||
| public String getRemotePath() { | public String getRemotePath() { | ||||
| return remotePath; | return remotePath; | ||||
| } | } | ||||
| /** | |||||
| * Set the file mode, defaults to 0644. | |||||
| * @since Ant 1.9.5 | |||||
| */ | |||||
| public void setFileMode(int fileMode) { | |||||
| this.fileMode = fileMode; | |||||
| } | |||||
| /** | |||||
| * Get the file mode. | |||||
| * @since Ant 1.9.5 | |||||
| */ | |||||
| public int getFileMode() { | |||||
| return fileMode != null ? fileMode.intValue() : DEFAULT_FILE_MODE; | |||||
| } | |||||
| /** | |||||
| * Set the dir mode, defaults to 0755. | |||||
| * @since Ant 1.9.5 | |||||
| */ | |||||
| public void setDirMode(int dirMode) { | |||||
| this.dirMode = dirMode; | |||||
| } | |||||
| /** | |||||
| * Get the dir mode. | |||||
| * @since Ant 1.9.5 | |||||
| */ | |||||
| public int getDirMode() { | |||||
| return dirMode != null ? dirMode.intValue() : DEFAULT_DIR_MODE; | |||||
| } | |||||
| } | } | ||||
| @@ -117,6 +117,7 @@ public class ScpToMessageBySftp extends ScpToMessage/*AbstractSshMessage*/ { | |||||
| * @throws IOException on i/o errors | * @throws IOException on i/o errors | ||||
| * @throws JSchException on errors detected by scp | * @throws JSchException on errors detected by scp | ||||
| */ | */ | ||||
| @Override | |||||
| public void execute() throws IOException, JSchException { | public void execute() throws IOException, JSchException { | ||||
| if (directoryList != null) { | if (directoryList != null) { | ||||
| doMultipleTransfer(); | doMultipleTransfer(); | ||||
| @@ -159,6 +160,7 @@ public class ScpToMessageBySftp extends ScpToMessage/*AbstractSshMessage*/ { | |||||
| if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) { | if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) { | ||||
| // dir does not exist. | // dir does not exist. | ||||
| channel.mkdir(remotePath); | channel.mkdir(remotePath); | ||||
| channel.chmod(getDirMode(), remotePath); | |||||
| } else { | } else { | ||||
| throw new JSchException("failed to access remote dir '" | throw new JSchException("failed to access remote dir '" | ||||
| + remotePath + "'", e); | + remotePath + "'", e); | ||||
| @@ -214,6 +216,7 @@ public class ScpToMessageBySftp extends ScpToMessage/*AbstractSshMessage*/ { | |||||
| // dir does not exist. | // dir does not exist. | ||||
| if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) { | if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) { | ||||
| channel.mkdir(dir); | channel.mkdir(dir); | ||||
| channel.chmod(getDirMode(), dir); | |||||
| } | } | ||||
| } | } | ||||
| channel.cd(dir); | channel.cd(dir); | ||||
| @@ -247,6 +250,7 @@ public class ScpToMessageBySftp extends ScpToMessage/*AbstractSshMessage*/ { | |||||
| log("Sending: " + localFile.getName() + " : " + filesize); | log("Sending: " + localFile.getName() + " : " + filesize); | ||||
| } | } | ||||
| channel.put(localFile.getAbsolutePath(), remotePath, monitor); | channel.put(localFile.getAbsolutePath(), remotePath, monitor); | ||||
| channel.chmod(getFileMode(), remotePath); | |||||
| } finally { | } finally { | ||||
| if (this.getVerbose()) { | if (this.getVerbose()) { | ||||
| final long endTime = System.currentTimeMillis(); | final long endTime = System.currentTimeMillis(); | ||||