You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2015/03/02 13:08:52 UTC

[1/4] mina-sshd git commit: [SSHD-423] DefaultSftpClient v4 'STAT' flags need to be initialized to 0xFFFF instead of 0

Repository: mina-sshd
Updated Branches:
  refs/heads/master e752d502a -> 91a721e94


[SSHD-423] DefaultSftpClient v4 'STAT' flags need to be initialized to 0xFFFF instead of 0


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/74f6b6c6
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/74f6b6c6
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/74f6b6c6

Branch: refs/heads/master
Commit: 74f6b6c6d971526c1d1fa1a28d32784050228430
Parents: e752d50
Author: Guillaume Nodet <gn...@apache.org>
Authored: Mon Mar 2 10:33:47 2015 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Mon Mar 2 10:33:47 2015 +0100

----------------------------------------------------------------------
 .../java/org/apache/sshd/client/sftp/DefaultSftpClient.java   | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/74f6b6c6/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
index 8ec2bb9..062ab55 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
@@ -40,6 +40,7 @@ import org.apache.sshd.client.SftpException;
 import org.apache.sshd.client.channel.ChannelSubsystem;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.server.sftp.SftpSubsystem;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -811,7 +812,7 @@ public class DefaultSftpClient implements SftpClient {
         Buffer buffer = new Buffer();
         buffer.putString(path);
         if (version >= SFTP_V4) {
-            buffer.putInt(0);
+            buffer.putInt(SftpSubsystem.SSH_FILEXFER_ATTR_ALL);
         }
         return checkAttributes(receive(send(SSH_FXP_STAT, buffer)));
     }
@@ -820,7 +821,7 @@ public class DefaultSftpClient implements SftpClient {
         Buffer buffer = new Buffer();
         buffer.putString(path);
         if (version >= SFTP_V4) {
-            buffer.putInt(0);
+            buffer.putInt(SftpSubsystem.SSH_FILEXFER_ATTR_ALL);
         }
         return checkAttributes(receive(send(SSH_FXP_LSTAT, buffer)));
     }
@@ -829,7 +830,7 @@ public class DefaultSftpClient implements SftpClient {
         Buffer buffer = new Buffer();
         buffer.putString(handle.id);
         if (version >= SFTP_V4) {
-            buffer.putInt(0);
+            buffer.putInt(SftpSubsystem.SSH_FILEXFER_ATTR_ALL);
         }
         return checkAttributes(receive(send(SSH_FXP_FSTAT, buffer)));
     }


[2/4] mina-sshd git commit: [SSHD-424] Avoid inadvertent closure of the input stream used by ScpHelper#receiveFile

Posted by gn...@apache.org.
[SSHD-424] Avoid inadvertent closure of the input stream used by ScpHelper#receiveFile

Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/687e7712
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/687e7712
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/687e7712

Branch: refs/heads/master
Commit: 687e77122cdaf57d4c19a248e2d97a87f0ce6294
Parents: 74f6b6c
Author: Guillaume Nodet <gn...@apache.org>
Authored: Mon Mar 2 10:43:19 2015 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Mon Mar 2 10:43:19 2015 +0100

----------------------------------------------------------------------
 .../org/apache/sshd/common/scp/ScpHelper.java   | 104 +++++++++++--------
 1 file changed, 59 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/687e7712/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
index 709de73..d73be2a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/scp/ScpHelper.java
@@ -255,51 +255,9 @@ public class ScpHelper {
         } else if (Files.exists(file) && !Files.isWritable(file)) {
             throw new IOException("Can not write to file: " + file);
         }
-        InputStream is = new FilterInputStream(in) {
-            long remaining = length;
-            @Override
-            public int read() throws IOException {
-                if (remaining > 0) {
-                    remaining--;
-                    return super.read();
-                } else{
-                    return -1;
-                }
-            }
-
-            @Override
-            public int read(byte[] b, int off, int len) throws IOException {
-                int nb = len;
-                if (nb > remaining) {
-                    nb = (int) remaining;
-                }
-                if (nb > 0) {
-                    int read = super.read(b, off, nb);
-                    remaining -= read;
-                    return read;
-                } else {
-                    return -1;
-                }
-            }
-
-            @Override
-            public long skip(long n) throws IOException {
-                long skipped = super.skip(n);
-                remaining -= skipped;
-                return skipped;
-            }
-
-            @Override
-            public int available() throws IOException {
-                int av = super.available();
-                if (av > remaining) {
-                    return (int) remaining;
-                } else {
-                    return av;
-                }
-            }
-        };
-        try (OutputStream os = Files.newOutputStream(file)) {
+        
+        try (InputStream is = new LimitInputStream(this.in, length);
+             OutputStream os = Files.newOutputStream(file)) {
             ack();
             IoUtils.copy(is, os, bufSize);
         }
@@ -625,4 +583,60 @@ public class ScpHelper {
         return c;
     }
 
+    private static class LimitInputStream extends FilterInputStream {
+
+        private long remaining;
+
+        public LimitInputStream(InputStream in, long length) {
+            super(in);
+            remaining = length;
+        }
+
+        @Override
+        public int read() throws IOException {
+            if (remaining > 0) {
+                remaining--;
+                return super.read();
+            } else{
+                return -1;
+            }
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            int nb = len;
+            if (nb > remaining) {
+                nb = (int) remaining;
+            }
+            if (nb > 0) {
+                int read = super.read(b, off, nb);
+                remaining -= read;
+                return read;
+            } else {
+                return -1;
+            }
+        }
+
+        @Override
+        public long skip(long n) throws IOException {
+            long skipped = super.skip(n);
+            remaining -= skipped;
+            return skipped;
+        }
+
+        @Override
+        public int available() throws IOException {
+            int av = super.available();
+            if (av > remaining) {
+                return (int) remaining;
+            } else {
+                return av;
+            }
+        }
+
+        @Override
+        public void close() throws IOException {
+            // do not close the original input stream since it serves for ACK(s)
+        }
+    }
 }


[3/4] mina-sshd git commit: [SSHD-425] Fix SFTP permission handling issues for Windows-based SSHD

Posted by gn...@apache.org.
[SSHD-425] Fix SFTP permission handling issues for Windows-based SSHD

Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/ef86ae54
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/ef86ae54
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/ef86ae54

Branch: refs/heads/master
Commit: ef86ae549598eb4393433b5d666c368415c15b30
Parents: 687e771
Author: Guillaume Nodet <gn...@apache.org>
Authored: Mon Mar 2 11:03:26 2015 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Mon Mar 2 13:00:48 2015 +0100

----------------------------------------------------------------------
 .../sshd/client/sftp/DefaultSftpClient.java     |  26 +++-
 .../client/sftp/SftpFileSystemProvider.java     |   6 +-
 .../org/apache/sshd/common/util/IoUtils.java    |  94 ++++++++++++++
 .../apache/sshd/server/sftp/SftpSubsystem.java  | 115 +++++++++--------
 .../src/test/java/org/apache/sshd/SftpTest.java | 125 ++++++++++---------
 5 files changed, 248 insertions(+), 118 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ef86ae54/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
index 062ab55..0389f6f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
@@ -109,6 +109,16 @@ public class DefaultSftpClient implements SftpClient {
     public static final int SSH_FXF_TRUNC =  0x00000010;
     public static final int SSH_FXF_EXCL =   0x00000020;
 
+    public static final int SSH_FILEXFER_TYPE_REGULAR =      1;
+    public static final int SSH_FILEXFER_TYPE_DIRECTORY =    2;
+    public static final int SSH_FILEXFER_TYPE_SYMLINK =      3;
+    public static final int SSH_FILEXFER_TYPE_SPECIAL =      4;
+    public static final int SSH_FILEXFER_TYPE_UNKNOWN =      5;
+    public static final int SSH_FILEXFER_TYPE_SOCKET =       6; // v5
+    public static final int SSH_FILEXFER_TYPE_CHAR_DEVICE =  7; // v5
+    public static final int SSH_FILEXFER_TYPE_BLOCK_DEVICE = 8; // v5
+    public static final int SSH_FILEXFER_TYPE_FIFO         = 9; // v5
+
     public static final int SSH_FXF_ACCESS_DISPOSITION = 0x00000007;
     public static final int SSH_FXF_CREATE_NEW =         0x00000000;
     public static final int SSH_FXF_CREATE_TRUNCATE =    0x00000001;
@@ -468,6 +478,20 @@ public class DefaultSftpClient implements SftpClient {
                 attrs.flags.add(Attribute.Perms);
                 attrs.perms = buffer.getInt();
             }
+            
+            // update the permissions according to the type
+            switch (attrs.type) {
+            case SSH_FILEXFER_TYPE_REGULAR:
+                attrs.perms |= S_IFREG;
+                break;
+            case SSH_FILEXFER_TYPE_DIRECTORY:
+                attrs.perms |= S_IFDIR;
+                break;
+            case SSH_FILEXFER_TYPE_SYMLINK:
+                attrs.perms |= S_IFLNK;
+                break;
+            }
+
             if ((flags & SSH_FILEXFER_ATTR_ACCESSTIME) != 0) {
                 attrs.flags.add(Attribute.AccessTime);
                 attrs.accessTime = readTime(buffer, flags);
@@ -485,7 +509,7 @@ public class DefaultSftpClient implements SftpClient {
             }
             // TODO: acl
         } else {
-            throw new IllegalStateException();
+            throw new IllegalStateException("readAttributes - unsupported version: " + version);
         }
         return attrs;
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ef86ae54/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
index 00d3d8a..c9f9a70 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
@@ -272,8 +272,7 @@ public class SftpFileSystemProvider extends FileSystemProvider {
             copyAttributes |= opt == StandardCopyOption.COPY_ATTRIBUTES;
             noFollowLinks |= opt == LinkOption.NOFOLLOW_LINKS;
         }
-        LinkOption[] linkOptions = noFollowLinks ? new LinkOption[] { LinkOption.NOFOLLOW_LINKS }
-                                                 : new LinkOption[0];
+        LinkOption[] linkOptions = IoUtils.getLinkOptions(!noFollowLinks);
 
         // attributes of source file
         BasicFileAttributes attrs = readAttributes(source,
@@ -334,8 +333,7 @@ public class SftpFileSystemProvider extends FileSystemProvider {
             copyAttributes |= opt == StandardCopyOption.COPY_ATTRIBUTES;
             noFollowLinks |= opt == LinkOption.NOFOLLOW_LINKS;
         }
-        LinkOption[] linkOptions = noFollowLinks ? new LinkOption[] { LinkOption.NOFOLLOW_LINKS }
-                : new LinkOption[0];
+        LinkOption[] linkOptions = IoUtils.getLinkOptions(noFollowLinks);
 
         // attributes of source file
         BasicFileAttributes attrs = readAttributes(source,

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ef86ae54/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
index 5a74cc3..cb21985 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/IoUtils.java
@@ -19,9 +19,18 @@
 package org.apache.sshd.common.util;
 
 import java.io.Closeable;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.file.LinkOption;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
 
 /**
  * TODO Add javadoc
@@ -30,6 +39,18 @@ import java.io.OutputStream;
  */
 public class IoUtils {
 
+    public static final LinkOption[] EMPTY_OPTIONS = new LinkOption[0];
+
+    private static final LinkOption[] NO_FOLLOW_OPTIONS = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+    
+    public static LinkOption[] getLinkOptions(boolean followLinks) {
+        if (followLinks) {
+            return EMPTY_OPTIONS;
+        } else {    // return a clone that modifications to the array will not affect others
+            return NO_FOLLOW_OPTIONS.clone();
+        }
+    }
+
     public static long copy(InputStream source, OutputStream sink) throws IOException {
         return copy(source, sink, 8192);
     }
@@ -57,4 +78,77 @@ public class IoUtils {
         }
     }
 
+    public static final List<String> WINDOWS_EXECUTABLE_EXTENSIONS = Collections.unmodifiableList(Arrays.asList(".bat", ".exe", ".cmd"));
+
+    /**
+     * @param fileName The file name to be evaluated - ignored if {@code null}/empty
+     * @return {@code true} if the file ends in one of the {@link #WINDOWS_EXECUTABLE_EXTENSIONS}
+     */
+    public static boolean isWindowsExecutable(String fileName) {
+        if ((fileName == null) || (fileName.length() <= 0)) {
+            return false;
+        }
+        for (String suffix : WINDOWS_EXECUTABLE_EXTENSIONS) {
+            if (fileName.endsWith(suffix)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param f The {@link File} to be checked
+     * @return A {@link Set} of {@link PosixFilePermission}s based on whether
+     * the file is readable/writable/executable. If so, then <U>all</U> the
+     * relevant permissions are set (i.e., owner, group and others)
+     */
+    public static Set<PosixFilePermission> getPermissionsFromFile(File f) {
+        Set<PosixFilePermission> perms = EnumSet.noneOf(PosixFilePermission.class);
+        if (f.canRead()) {
+            perms.add(PosixFilePermission.OWNER_READ);
+            perms.add(PosixFilePermission.GROUP_READ);
+            perms.add(PosixFilePermission.OTHERS_READ);
+        }
+
+        if (f.canWrite()) {
+            perms.add(PosixFilePermission.OWNER_WRITE);
+            perms.add(PosixFilePermission.GROUP_WRITE);
+            perms.add(PosixFilePermission.OTHERS_WRITE);
+        }
+
+        if (f.canExecute() || (OsUtils.isWin32() && isWindowsExecutable(f.getName()))) {
+            perms.add(PosixFilePermission.OWNER_EXECUTE);
+            perms.add(PosixFilePermission.GROUP_EXECUTE);
+            perms.add(PosixFilePermission.OTHERS_EXECUTE);
+        }
+
+        return perms;
+    }
+    
+    /**
+     * @param f The {@link File}
+     * @param perms A {@link Collection} of {@link PosixFilePermission}s to set on it.
+     * <B>Note:</B> the file is set to readable/writable/executable not only by the
+     * owner if <U>any</U> of relevant the owner/group/others permission is set
+     */
+    public static void setPermissionsToFile(File f, Collection<PosixFilePermission> perms) {
+        boolean readable = perms != null &&
+                  (perms.contains(PosixFilePermission.OWNER_READ)
+                || perms.contains(PosixFilePermission.GROUP_READ)
+                || perms.contains(PosixFilePermission.OTHERS_READ));
+        f.setReadable(readable, false);
+
+        boolean writable = perms != null &&
+                  (perms.contains(PosixFilePermission.OWNER_WRITE)
+                || perms.contains(PosixFilePermission.GROUP_WRITE)
+                || perms.contains(PosixFilePermission.OTHERS_WRITE));
+        f.setWritable(writable, false);
+
+        boolean executable = perms != null &&
+                  (perms.contains(PosixFilePermission.OWNER_EXECUTE)
+                || perms.contains(PosixFilePermission.GROUP_EXECUTE)
+                || perms.contains(PosixFilePermission.OTHERS_EXECUTE));
+        f.setExecutable(executable, false);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ef86ae54/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
index 0f0e9d8..963f90a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
@@ -78,6 +78,8 @@ import java.util.concurrent.TimeUnit;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.file.FileSystemAware;
 import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.common.util.IoUtils;
+import org.apache.sshd.common.util.OsUtils;
 import org.apache.sshd.common.util.SelectorUtils;
 import org.apache.sshd.common.util.ThreadUtils;
 import org.apache.sshd.server.Command;
@@ -1589,12 +1591,8 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
         return sb.toString();
     }
 
-    protected int attributesToPermissions(Map<String, Object> attributes) {
-        boolean isReg = getBool((Boolean) attributes.get("isRegularFile"));
-        boolean isDir = getBool((Boolean) attributes.get("isDirectory"));
-        boolean isLnk = getBool((Boolean) attributes.get("isSymbolicLink"));
+    protected int attributesToPermissions(boolean isReg, boolean isDir, boolean isLnk, Collection<PosixFilePermission> perms) {
         int pf = 0;
-        Set<PosixFilePermission> perms = (Set<PosixFilePermission>) attributes.get("permissions");
         if (perms != null) {
             for (PosixFilePermission p : perms) {
                 switch (p) {
@@ -1635,7 +1633,7 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
     }
 
     protected void writeAttrs(Buffer buffer, Path file, int flags, boolean followLinks) throws IOException {
-        LinkOption[] options = followLinks ? new LinkOption[0] : new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+        LinkOption[] options = IoUtils.getLinkOptions(followLinks);
         if (!Files.exists(file, options)) {
             throw new FileNotFoundException(file.toString());
         }
@@ -1644,79 +1642,69 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
     }
 
     protected void writeAttrs(Buffer buffer, Map<String, Object> attributes) throws IOException {
+        boolean isReg = getBool((Boolean) attributes.get("isRegularFile"));
+        boolean isDir = getBool((Boolean) attributes.get("isDirectory"));
+        boolean isLnk = getBool((Boolean) attributes.get("isSymbolicLink"));
+        @SuppressWarnings("unchecked")
+        Collection<PosixFilePermission> perms = (Collection<PosixFilePermission>) attributes.get("permissions");
+        Number size = (Number) attributes.get("size");
+        FileTime lastModifiedTime = (FileTime) attributes.get("lastModifiedTime");
+        FileTime lastAccessTime = (FileTime) attributes.get("lastAccessTime");
+
         if (version == SFTP_V3) {
-            boolean isReg = getBool((Boolean) attributes.get("isRegularFile"));
-            boolean isDir = getBool((Boolean) attributes.get("isDirectory"));
-            boolean isLnk = getBool((Boolean) attributes.get("isSymbolicLink"));
             int flags =
-                    ((isReg || isLnk) && attributes.containsKey("size") ? SSH_FILEXFER_ATTR_SIZE : 0) |
+                    ((isReg || isLnk) && (size != null) ? SSH_FILEXFER_ATTR_SIZE : 0) |
                     (attributes.containsKey("uid") && attributes.containsKey("gid") ? SSH_FILEXFER_ATTR_UIDGID : 0) |
-                    (attributes.containsKey("permissions") ? SSH_FILEXFER_ATTR_PERMISSIONS : 0) |
-                    (attributes.containsKey("lastModifiedTime") && attributes.containsKey("lastAccessTime") ? SSH_FILEXFER_ATTR_ACMODTIME : 0);
+                    ((perms != null) ? SSH_FILEXFER_ATTR_PERMISSIONS : 0) |
+                    (((lastModifiedTime != null) && (lastAccessTime != null)) ? SSH_FILEXFER_ATTR_ACMODTIME : 0);
             buffer.putInt(flags);
             if ((flags & SSH_FILEXFER_ATTR_SIZE) != 0) {
-                buffer.putLong((Long) attributes.get("size"));
+                buffer.putLong(size.longValue());
             }
             if ((flags & SSH_FILEXFER_ATTR_UIDGID) != 0) {
-                buffer.putInt((Integer) attributes.get("uid"));
-                buffer.putInt((Integer) attributes.get("gid"));
+                buffer.putInt(((Number) attributes.get("uid")).intValue());
+                buffer.putInt(((Number) attributes.get("gid")).intValue());
             }
             if ((flags & SSH_FILEXFER_ATTR_PERMISSIONS) != 0) {
-                buffer.putInt(attributesToPermissions(attributes));
+                buffer.putInt(attributesToPermissions(isReg, isDir, isLnk, perms));
             }
             if ((flags & SSH_FILEXFER_ATTR_ACMODTIME) != 0) {
-                buffer.putInt(((FileTime) attributes.get("lastAccessTime")).to(TimeUnit.SECONDS));
-                buffer.putInt(((FileTime) attributes.get("lastModifiedTime")).to(TimeUnit.SECONDS));
+                buffer.putInt(lastAccessTime.to(TimeUnit.SECONDS));
+                buffer.putInt(lastModifiedTime.to(TimeUnit.SECONDS));
             }
         } else if (version >= SFTP_V4) {
-            boolean isReg = getBool((Boolean) attributes.get("isRegularFile"));
-            boolean isDir = getBool((Boolean) attributes.get("isDirectory"));
-            boolean isLnk = getBool((Boolean) attributes.get("isSymbolicLink"));
-            int flags =
-                    ((isReg || isLnk) && attributes.containsKey("size") ? SSH_FILEXFER_ATTR_SIZE : 0) |
-                            (attributes.containsKey("owner") && attributes.containsKey("group") ? SSH_FILEXFER_ATTR_OWNERGROUP : 0) |
-                            (attributes.containsKey("permissions") ? SSH_FILEXFER_ATTR_PERMISSIONS : 0) |
-                            (attributes.containsKey("lastModifiedTime") ? SSH_FILEXFER_ATTR_MODIFYTIME : 0) |
-                            (attributes.containsKey("creationTime") ? SSH_FILEXFER_ATTR_CREATETIME : 0) |
-                            (attributes.containsKey("lastAccessTime") ? SSH_FILEXFER_ATTR_ACCESSTIME : 0);
+            FileTime creationTime = (FileTime) attributes.get("creationTime");
+            int flags = (((isReg || isLnk) && (size != null)) ? SSH_FILEXFER_ATTR_SIZE : 0) |
+                        ((attributes.containsKey("owner") && attributes.containsKey("group")) ? SSH_FILEXFER_ATTR_OWNERGROUP : 0) |
+                        ((perms != null) ? SSH_FILEXFER_ATTR_PERMISSIONS : 0) |
+                        ((lastModifiedTime != null) ? SSH_FILEXFER_ATTR_MODIFYTIME : 0) |
+                        ((creationTime != null) ? SSH_FILEXFER_ATTR_CREATETIME : 0) |
+                        ((lastAccessTime != null) ? SSH_FILEXFER_ATTR_ACCESSTIME : 0);
             buffer.putInt(flags);
             buffer.putByte((byte) (isReg ? SSH_FILEXFER_TYPE_REGULAR :
                     isDir ? SSH_FILEXFER_TYPE_DIRECTORY :
                             isLnk ? SSH_FILEXFER_TYPE_SYMLINK :
                                     SSH_FILEXFER_TYPE_UNKNOWN));
             if ((flags & SSH_FILEXFER_ATTR_SIZE) != 0) {
-                buffer.putLong((Long) attributes.get("size"));
+                buffer.putLong(size.longValue());
             }
             if ((flags & SSH_FILEXFER_ATTR_OWNERGROUP) != 0) {
                 buffer.putString(attributes.get("owner").toString(), StandardCharsets.UTF_8);
                 buffer.putString(attributes.get("group").toString(), StandardCharsets.UTF_8);
             }
             if ((flags & SSH_FILEXFER_ATTR_PERMISSIONS) != 0) {
-                buffer.putInt(attributesToPermissions(attributes));
+                buffer.putInt(attributesToPermissions(isReg, isDir, isLnk, perms));
             }
+
             if ((flags & SSH_FILEXFER_ATTR_ACCESSTIME) != 0) {
-                buffer.putLong(((FileTime) attributes.get("lastAccessTime")).to(TimeUnit.SECONDS));
-                if ((flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) != 0) {
-                    long nanos = ((FileTime) attributes.get("lastAccessTime")).to(TimeUnit.NANOSECONDS);
-                    nanos = nanos % TimeUnit.SECONDS.toNanos(1);
-                    buffer.putInt((int) nanos);
-                }
+                putFileTime(buffer, flags, lastAccessTime);
             }
+
             if ((flags & SSH_FILEXFER_ATTR_CREATETIME) != 0) {
-                buffer.putLong(((FileTime) attributes.get("creationTime")).to(TimeUnit.SECONDS));
-                if ((flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) != 0) {
-                    long nanos = ((FileTime) attributes.get("creationTime")).to(TimeUnit.NANOSECONDS);
-                    nanos = nanos % TimeUnit.SECONDS.toNanos(1);
-                    buffer.putInt((int) nanos);
-                }
+                putFileTime(buffer, flags, lastAccessTime);
             }
             if ((flags & SSH_FILEXFER_ATTR_MODIFYTIME) != 0) {
-                buffer.putLong(((FileTime) attributes.get("lastModifiedTime")).to(TimeUnit.SECONDS));
-                if ((flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) != 0) {
-                    long nanos = ((FileTime) attributes.get("lastModifiedTime")).to(TimeUnit.NANOSECONDS);
-                    nanos = nanos % TimeUnit.SECONDS.toNanos(1);
-                    buffer.putInt((int) nanos);
-                }
+                putFileTime(buffer, flags, lastModifiedTime);
             }
             // TODO: acls
             // TODO: bits
@@ -1724,6 +1712,15 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
         }
     }
 
+    protected void putFileTime(Buffer buffer, int flags, FileTime time) {
+        buffer.putLong(time.to(TimeUnit.SECONDS));
+        if ((flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) != 0) {
+            long nanos = time.to(TimeUnit.NANOSECONDS);
+            nanos = nanos % TimeUnit.SECONDS.toNanos(1);
+            buffer.putInt((int) nanos);
+        }
+    }
+
     protected boolean getBool(Boolean bool) {
         return bool != null && bool;
     }
@@ -1733,17 +1730,22 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
     }
 
     protected Map<String, Object> getAttributes(Path file, int flags, boolean followLinks) throws IOException {
-        Set<String> views = file.getFileSystem().supportedFileAttributeViews();
-        LinkOption[] opts = followLinks ? new LinkOption[0] : new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+        FileSystem fs = file.getFileSystem();
+        Collection<String> views = fs.supportedFileAttributeViews();
+        LinkOption[] opts = IoUtils.getLinkOptions(followLinks);
         // TODO: support flags
         if (views.contains("unix")) {
             return Files.readAttributes(file, "unix:*", opts);
         } else {
             Map<String, Object> a = new HashMap<>();
-            for (String view : file.getFileSystem().supportedFileAttributeViews()) {
+            for (String view : views) {
                 Map<String, Object> ta = Files.readAttributes(file, view + ":*", opts);
                 a.putAll(ta);
             }
+            if (OsUtils.isWin32() && (!a.containsKey("permissions"))) {
+                Set<PosixFilePermission> perms = IoUtils.getPermissionsFromFile(file.toFile());
+                a.put("permissions", perms);
+            }
             return a;
         }
     }
@@ -1765,7 +1767,16 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
             case "gid":              view = "unix"; break;
             case "owner":            view = "posix"; value = toUser(file, (UserPrincipal) value); break;
             case "group":            view = "posix"; value = toGroup(file, (GroupPrincipal) value); break;
-            case "permissions":      view = "posix"; break;
+            case "permissions":
+                if (OsUtils.isWin32()) {
+                    @SuppressWarnings("unchecked")
+                    Collection<PosixFilePermission> perms = (Collection<PosixFilePermission>) value;
+                    IoUtils.setPermissionsToFile(file.toFile(), perms);
+                    continue;
+                }
+                view = "posix";
+                break;
+
             case "creationTime":     view = "basic"; break;
             case "lastModifiedTime": view = "basic"; break;
             case "lastAccessTime":   view = "basic"; break;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ef86ae54/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
index 495e94e..71d6f20 100644
--- a/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
@@ -184,69 +184,72 @@ public class SftpTest extends BaseTest {
     public void testClient() throws Exception {
         SshClient client = SshClient.setUpDefaultClient();
         client.start();
-        ClientSession session = client.connect("x", "localhost", port).await().getSession();
-        session.addPasswordIdentity("x");
-        session.auth().verify();
-
-        Utils.deleteRecursive(new File("target/sftp"));
-        new File("target/sftp").mkdirs();
-        new File("target/sftp/client/test.txt").delete();
-        new File("target/sftp/client").delete();
-
-        try(SftpClient sftp = session.createSftpClient()) {
-            sftp.mkdir("target/sftp/client");
-    
-            SftpClient.Handle h = sftp.open("target/sftp/client/test.txt", EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create));
-            byte[] d = "0123456789\n".getBytes();
-            sftp.write(h, 0, d, 0, d.length);
-            sftp.write(h, d.length, d, 0, d.length);
-    
-            SftpClient.Attributes attrs = sftp.stat(h);
-            assertNotNull("No handle attributes", attrs);
-    
-            sftp.close(h);
-    
-            h = sftp.openDir("target/sftp/client");
-            SftpClient.DirEntry[] dir = sftp.readDir(h);
-            assertNotNull("No dir entries", dir);
-            assertEquals("Mismatced number of dir entries", 1, dir.length);
-            assertNull("Unexpected entry read", sftp.readDir(h));
-            sftp.close(h);
-    
-            sftp.remove("target/sftp/client/test.txt");
-    
-            byte[]  workBuf=new byte[1024 * 128];
-            try(OutputStream os = sftp.write("target/sftp/client/test.txt")) {
-                os.write(workBuf);
-            }
-    
-            try(InputStream is = sftp.read("target/sftp/client/test.txt")) {
-                int readLen=is.read(workBuf);
-                assertEquals("Mismatched read data length", workBuf.length, readLen);
-
-                int i = is.read();
-                assertEquals("Unexpected read past EOF", -1, i);
-            }
-
-            SftpClient.Attributes attributes = sftp.stat("target/sftp/client/test.txt");
-            assertTrue("Test file not detected as regular", attributes.isRegularFile());
-    
-            attributes = sftp.stat("target/sftp/client");
-            assertTrue("Test directory not reported as such", attributes.isDirectory());
-    
-            int nb = 0;
-            for (SftpClient.DirEntry entry : sftp.readDir("target/sftp/client")) {
-                assertNotNull("Unexpected null entry", entry);
-                nb++;
+        try {
+            try (ClientSession session = client.connect("x", "localhost", port).await().getSession()) {
+                session.addPasswordIdentity("x");
+                session.auth().verify();
+        
+                Utils.deleteRecursive(new File("target/sftp"));
+                new File("target/sftp").mkdirs();
+                new File("target/sftp/client/test.txt").delete();
+                new File("target/sftp/client").delete();
+        
+                try (SftpClient sftp = session.createSftpClient()) {
+                    sftp.mkdir("target/sftp/client");
+            
+                    SftpClient.Handle h = sftp.open("target/sftp/client/test.txt", EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create));
+                    byte[] d = "0123456789\n".getBytes();
+                    sftp.write(h, 0, d, 0, d.length);
+                    sftp.write(h, d.length, d, 0, d.length);
+            
+                    SftpClient.Attributes attrs = sftp.stat(h);
+                    assertNotNull("No handle attributes", attrs);
+            
+                    sftp.close(h);
+            
+                    h = sftp.openDir("target/sftp/client");
+                    SftpClient.DirEntry[] dir = sftp.readDir(h);
+                    assertNotNull("No dir entries", dir);
+                    assertEquals("Mismatced number of dir entries", 1, dir.length);
+                    assertNull("Unexpected entry read", sftp.readDir(h));
+                    sftp.close(h);
+            
+                    sftp.remove("target/sftp/client/test.txt");
+
+                    byte[] workBuf = new byte[1024 * 128];
+                    try (OutputStream os = sftp.write("target/sftp/client/test.txt")) {
+                        os.write(workBuf);
+                    }
+            
+                    try (InputStream is = sftp.read("target/sftp/client/test.txt")) {
+                        int readLen = is.read(workBuf);
+                        assertEquals("Mismatched read data length", workBuf.length, readLen);
+        
+                        int i = is.read();
+                        assertEquals("Unexpected read past EOF", -1, i);
+                    }
+        
+                    SftpClient.Attributes attributes = sftp.stat("target/sftp/client/test.txt");
+                    assertTrue("Test file not detected as regular", attributes.isRegularFile());
+            
+                    attributes = sftp.stat("target/sftp/client");
+                    assertTrue("Test directory not reported as such", attributes.isDirectory());
+            
+                    int nb = 0;
+                    for (SftpClient.DirEntry entry : sftp.readDir("target/sftp/client")) {
+                        assertNotNull("Unexpected null entry", entry);
+                        nb++;
+                    }
+                    assertEquals("Mismatched read dir entries", 1, nb);
+            
+                    sftp.remove("target/sftp/client/test.txt");
+            
+                    sftp.rmdir("target/sftp/client/");
+                }
             }
-            assertEquals("Mismatched read dir entries", 1, nb);
-    
-            sftp.remove("target/sftp/client/test.txt");
-    
-            sftp.rmdir("target/sftp/client/");
+        } finally {
+            client.stop();
         }
-
-        client.stop();
     }
 
     /**


[4/4] mina-sshd git commit: [SSHD-426] Fix SftpTest#testOpen code to take into account Windows behavior

Posted by gn...@apache.org.
[SSHD-426] Fix SftpTest#testOpen code to take into account Windows behavior


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/91a721e9
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/91a721e9
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/91a721e9

Branch: refs/heads/master
Commit: 91a721e945c961b3c02e940805ba1a0f0d696fb6
Parents: ef86ae5
Author: Guillaume Nodet <gn...@apache.org>
Authored: Mon Mar 2 11:07:05 2015 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Mon Mar 2 13:00:54 2015 +0100

----------------------------------------------------------------------
 .../java/org/apache/sshd/client/SftpClient.java |   4 +-
 .../sshd/client/sftp/DefaultSftpClient.java     |   3 +-
 .../apache/sshd/client/sftp/SftpFileSystem.java |   3 +-
 .../apache/sshd/server/sftp/SftpSubsystem.java  |   8 +-
 .../src/test/java/org/apache/sshd/SftpTest.java | 169 ++++++++++---------
 5 files changed, 98 insertions(+), 89 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/91a721e9/sshd-core/src/main/java/org/apache/sshd/client/SftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/SftpClient.java
index 5c5aeb5..4001aaf 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/SftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/SftpClient.java
@@ -21,8 +21,8 @@ package org.apache.sshd.client;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.nio.ByteBuffer;
 import java.nio.file.attribute.FileTime;
+import java.util.Collection;
 import java.util.EnumSet;
 import java.util.concurrent.TimeUnit;
 
@@ -214,7 +214,7 @@ public interface SftpClient extends AutoCloseable {
     // Low level API
     //
 
-    Handle open(String path, EnumSet<OpenMode> options) throws IOException;
+    Handle open(String path, Collection<OpenMode> options) throws IOException;
 
     void close(Handle handle) throws IOException;
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/91a721e9/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
index 0389f6f..a793cc6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/DefaultSftpClient.java
@@ -27,6 +27,7 @@ import java.io.InterruptedIOException;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.attribute.FileTime;
+import java.util.Collection;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -627,7 +628,7 @@ public class DefaultSftpClient implements SftpClient {
         }
     }
 
-    public Handle open(String path, EnumSet<OpenMode> options) throws IOException {
+    public Handle open(String path, Collection<OpenMode> options) throws IOException {
         Buffer buffer = new Buffer();
         buffer.putString(path);
         if (version == SFTP_V3) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/91a721e9/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java
index 98d6679..734a3e2 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java
@@ -25,6 +25,7 @@ import java.nio.file.attribute.GroupPrincipal;
 import java.nio.file.attribute.UserPrincipal;
 import java.nio.file.attribute.UserPrincipalLookupService;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashSet;
@@ -142,7 +143,7 @@ public class SftpFileSystem extends BaseFileSystem<SftpPath> {
         }
 
         @Override
-        public Handle open(String path, EnumSet<OpenMode> options) throws IOException {
+        public Handle open(String path, Collection<OpenMode> options) throws IOException {
             return delegate.open(path, options);
         }
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/91a721e9/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
index 963f90a..16fc902 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
@@ -392,7 +392,7 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
     private UnsupportedAttributePolicy unsupportedAttributePolicy = UnsupportedAttributePolicy.Warn;
 
     protected static abstract class Handle implements java.io.Closeable {
-        Path file;
+        private Path file;
 
         public Handle(Path file) {
             this.file = file;
@@ -453,9 +453,9 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
     }
 
     protected class FileHandle extends Handle {
-        final FileChannel channel;
-        long pos;
-        final List<FileLock> locks = new ArrayList<>();
+        private final FileChannel channel;
+        private long pos;
+        private final List<FileLock> locks = new ArrayList<>();
 
         public FileHandle(Path file, int flags, int access, Map<String, Object> attrs) throws IOException {
             super(file);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/91a721e9/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
index 71d6f20..78cb70a 100644
--- a/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
@@ -95,89 +95,96 @@ public class SftpTest extends BaseTest {
     public void testOpen() throws Exception {
         SshClient client = SshClient.setUpDefaultClient();
         client.start();
-        ClientSession session = client.connect("x", "localhost", port).await().getSession();
-        session.addPasswordIdentity("x");
-        session.auth().verify();
-
-        String file = "target/sftp/client/testOpen.txt";
-        File javaFile = new File(file);
-
-        javaFile.getParentFile().mkdirs();
-        javaFile.createNewFile();
-        javaFile.setWritable(false, false);
-        javaFile.setReadable(false, false);
-
-        SftpClient sftp = session.createSftpClient();
-        SftpClient.Handle h;
-
-        boolean	isWindows = OsUtils.isWin32();
-
-        try {
-            h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
-            // NOTE: on Windows files are always readable
-            // see https://svn.apache.org/repos/asf/harmony/enhanced/java/branches/java6/classlib/modules/luni/src/test/api/windows/org/apache/harmony/luni/tests/java/io/WinFileTest.java
-            Assert.assertTrue("Empty read should have failed", isWindows);
-            sftp.close(h);
-        } catch (IOException e) {
-            if (isWindows) {
-                throw e;
-            }
-        }
-
-        try {
-            h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
-            fail("Empty write should have failed");
-        } catch (IOException e) {
-            // ok
-        }
-
-        try {
-            h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate));
-            fail("Empty truncate should have failed");
-        } catch (IOException e) {
-            // ok
-        }
-
-        // NOTE: on Windows files are always readable
-        int	perms=sftp.stat(file).perms;
-        int	permsMask=SftpClient.S_IWUSR | (isWindows ? 0 : SftpClient.S_IRUSR);
-        Assert.assertEquals("Mismatched permissions - 0x" + Integer.toHexString(perms), 0, (perms & permsMask));
-
-        javaFile.setWritable(true, false);
-
-        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate, SftpClient.OpenMode.Write));
-        sftp.close(h);
-
-        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
-        byte[] d = "0123456789\n".getBytes();
-        sftp.write(h, 0, d, 0, d.length);
-        sftp.write(h, d.length, d, 0, d.length);
-        sftp.close(h);
-        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
-        sftp.write(h, d.length * 2, d, 0, d.length);
-        sftp.close(h);
-        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
-        sftp.write(h, 3, "-".getBytes(), 0, 1);
-        sftp.close(h);
-
-        try {
-            h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
-            // NOTE: on Windows files are always readable
-            Assert.assertTrue("Data read should have failed", isWindows);
-            sftp.close(h);
-        } catch (IOException e) {
-            if (isWindows) {
-                throw e;
+        
+        try (ClientSession session = client.connect("x", "localhost", port).await().getSession()) {
+            session.addPasswordIdentity("x");
+            session.auth().verify();
+    
+            String file = "target/sftp/client/testOpen.txt";
+            File javaFile = new File(file);
+    
+            assertHierarchyTargetFolderExists(javaFile.getParentFile());
+            javaFile.createNewFile();
+            javaFile.setWritable(false, false);
+            javaFile.setReadable(false, false);
+    
+            try (SftpClient sftp = session.createSftpClient()) {
+                SftpClient.Handle h;
+        
+                boolean	isWindows = OsUtils.isWin32();
+        
+                try {
+                    h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
+                    // NOTE: on Windows files are always readable
+                    // see https://svn.apache.org/repos/asf/harmony/enhanced/java/branches/java6/classlib/modules/luni/src/test/api/windows/org/apache/harmony/luni/tests/java/io/WinFileTest.java
+                    Assert.assertTrue("Empty read should have failed", isWindows);
+                    sftp.close(h);
+                } catch (IOException e) {
+                    if (isWindows) {
+                        throw e;
+                    }
+                }
+        
+                try {
+                    h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
+                    fail("Empty write should have failed");
+                } catch (IOException e) {
+                    // ok
+                }
+        
+                try {
+                    h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate));
+                    // NOTE: on Windows files are always readable
+                    Assert.assertTrue("Empty truncate should have failed", isWindows);
+                    sftp.close(h);
+                } catch (IOException e) {
+                    // ok
+                }
+        
+                // NOTE: on Windows files are always readable
+                int	perms=sftp.stat(file).perms;
+                int	permsMask=SftpClient.S_IWUSR | (isWindows ? 0 : SftpClient.S_IRUSR);
+                Assert.assertEquals("Mismatched permissions - 0x" + Integer.toHexString(perms), 0, (perms & permsMask));
+        
+                javaFile.setWritable(true, false);
+        
+                h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate, SftpClient.OpenMode.Write));
+                sftp.close(h);
+        
+                h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
+                byte[] d = "0123456789\n".getBytes();
+                sftp.write(h, 0, d, 0, d.length);
+                sftp.write(h, d.length, d, 0, d.length);
+                sftp.close(h);
+                h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
+                sftp.write(h, d.length * 2, d, 0, d.length);
+                sftp.close(h);
+                h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
+                sftp.write(h, 3, "-".getBytes(), 0, 1);
+                sftp.close(h);
+        
+                try {
+                    h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
+                    // NOTE: on Windows files are always readable
+                    Assert.assertTrue("Data read should have failed", isWindows);
+                    sftp.close(h);
+                } catch (IOException e) {
+                    if (isWindows) {
+                        throw e;
+                    }
+                }
+        
+                javaFile.setReadable(true, false);
+        
+                h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
+                byte[] buf = new byte[3];
+                int l = sftp.read(h, 2l, buf, 0, 3);
+                assertEquals("Mismatched read data", "2-4", new String(buf, 0, l));
+                sftp.close(h);
             }
+        } finally {
+            client.stop();
         }
-
-        javaFile.setReadable(true, false);
-
-        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
-        byte[] buf = new byte[3];
-        int l = sftp.read(h, 2l, buf, 0, 3);
-        assertEquals("Mismatched read data", "2-4", new String(buf, 0, l));
-        sftp.close(h);
     }
 
     @Test