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-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 | |||
| =================================== | |||
| @@ -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> | |||
| <td valign="top" align="center">No; defaults to false.</td> | |||
| </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> | |||
| <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><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 | |||
| permissions in the current Java runtimes. If you need a permission- | |||
| preserving copy function, use <code><exec executable="scp" ... ></code> | |||
| @@ -52,6 +52,7 @@ public class Scp extends SSHBase { | |||
| private List fileSets = null; | |||
| private boolean isFromRemote, isToRemote; | |||
| private boolean isSftp = false; | |||
| private Integer fileMode, dirMode; | |||
| /** | |||
| * Sets the file to be transferred. This can either be a remote | |||
| @@ -180,6 +181,22 @@ public class Scp extends SSHBase { | |||
| 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 | |||
| * addFileSet() or setFile() are required. But, not both. | |||
| @@ -307,6 +324,12 @@ public class Scp extends SSHBase { | |||
| list, file); | |||
| } | |||
| message.setLogListener(this); | |||
| if (fileMode != null) { | |||
| message.setFileMode(fileMode.intValue()); | |||
| } | |||
| if (dirMode != null) { | |||
| message.setDirMode(dirMode.intValue()); | |||
| } | |||
| message.execute(); | |||
| } | |||
| } finally { | |||
| @@ -335,6 +358,12 @@ public class Scp extends SSHBase { | |||
| file); | |||
| } | |||
| message.setLogListener(this); | |||
| if (fileMode != null) { | |||
| message.setFileMode(fileMode.intValue()); | |||
| } | |||
| if (dirMode != null) { | |||
| message.setDirMode(dirMode.intValue()); | |||
| } | |||
| message.execute(); | |||
| } finally { | |||
| if (session != null) { | |||
| @@ -37,10 +37,13 @@ public class ScpToMessage extends AbstractSshMessage { | |||
| private static final int HUNDRED_KILOBYTES = 102400; | |||
| 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 String remotePath; | |||
| private List directoryList; | |||
| private Integer fileMode, dirMode; | |||
| /** | |||
| * Constructor for ScpToMessage | |||
| @@ -137,6 +140,7 @@ public class ScpToMessage extends AbstractSshMessage { | |||
| * @throws IOException on i/o errors | |||
| * @throws JSchException on errors detected by scp | |||
| */ | |||
| @Override | |||
| public void execute() throws IOException, JSchException { | |||
| if (directoryList != null) { | |||
| doMultipleTransfer(); | |||
| @@ -201,7 +205,9 @@ public class ScpToMessage extends AbstractSshMessage { | |||
| private void sendDirectoryToRemote(final Directory directory, | |||
| final InputStream in, | |||
| final OutputStream out) throws IOException { | |||
| String command = "D0755 0 "; | |||
| String command = "D0"; | |||
| command += Integer.toOctalString(getDirMode()); | |||
| command += " 0 "; | |||
| command += directory.getDirectory().getName(); | |||
| command += "\n"; | |||
| @@ -220,7 +226,9 @@ public class ScpToMessage extends AbstractSshMessage { | |||
| final OutputStream out) throws IOException { | |||
| // send "C0644 filesize filename", where filename should not include '/' | |||
| final long filesize = localFile.length(); | |||
| String command = "C0644 " + filesize + " "; | |||
| String command = "C0"; | |||
| command += Integer.toOctalString(getFileMode()); | |||
| command += " " + filesize + " "; | |||
| command += localFile.getName(); | |||
| command += "\n"; | |||
| @@ -287,4 +295,37 @@ public class ScpToMessage extends AbstractSshMessage { | |||
| public String getRemotePath() { | |||
| 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 JSchException on errors detected by scp | |||
| */ | |||
| @Override | |||
| public void execute() throws IOException, JSchException { | |||
| if (directoryList != null) { | |||
| doMultipleTransfer(); | |||
| @@ -159,6 +160,7 @@ public class ScpToMessageBySftp extends ScpToMessage/*AbstractSshMessage*/ { | |||
| if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) { | |||
| // dir does not exist. | |||
| channel.mkdir(remotePath); | |||
| channel.chmod(getDirMode(), remotePath); | |||
| } else { | |||
| throw new JSchException("failed to access remote dir '" | |||
| + remotePath + "'", e); | |||
| @@ -214,6 +216,7 @@ public class ScpToMessageBySftp extends ScpToMessage/*AbstractSshMessage*/ { | |||
| // dir does not exist. | |||
| if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) { | |||
| channel.mkdir(dir); | |||
| channel.chmod(getDirMode(), dir); | |||
| } | |||
| } | |||
| channel.cd(dir); | |||
| @@ -247,6 +250,7 @@ public class ScpToMessageBySftp extends ScpToMessage/*AbstractSshMessage*/ { | |||
| log("Sending: " + localFile.getName() + " : " + filesize); | |||
| } | |||
| channel.put(localFile.getAbsolutePath(), remotePath, monitor); | |||
| channel.chmod(getFileMode(), remotePath); | |||
| } finally { | |||
| if (this.getVerbose()) { | |||
| final long endTime = System.currentTimeMillis(); | |||