[SSHD-317] UnsupportedOperationException uploading file Java 7/Windows Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/97b38fb0 Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/97b38fb0 Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/97b38fb0
Branch: refs/heads/master Commit: 97b38fb08e4a4fffb8fb01dd9d30ac2a2af16dee Parents: 29ff339 Author: Guillaume Nodet <[email protected]> Authored: Mon Jun 16 14:21:35 2014 +0200 Committer: Guillaume Nodet <[email protected]> Committed: Mon Jun 16 14:21:35 2014 +0200 ---------------------------------------------------------------------- .../file/nativefs/NativeFileSystemView.java | 18 ++++- .../common/file/nativefs/NativeSshFile.java | 44 ++++++++++- .../common/file/nativefs/NativeSshFileNio.java | 81 ++++++++++++++++---- 3 files changed, 125 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/97b38fb0/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemView.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemView.java b/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemView.java index 9816b1e..9337349 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemView.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeFileSystemView.java @@ -45,6 +45,12 @@ import static org.apache.sshd.common.file.nativefs.NativeSshFile.normalizeSepara */ public class NativeFileSystemView implements FileSystemView { + public enum UnsupportedAttributePolicy { + Ignore, + Warn, + ThrowException + } + private final Logger LOG = LoggerFactory.getLogger(NativeFileSystemView.class); @@ -60,6 +66,8 @@ public class NativeFileSystemView implements FileSystemView { private boolean caseInsensitive = false; + private UnsupportedAttributePolicy unsupportedAttributePolicy = UnsupportedAttributePolicy.Warn; + /** * Constructor - internal do not use directly, use {@link NativeFileSystemFactory} instead */ @@ -141,6 +149,14 @@ public class NativeFileSystemView implements FileSystemView { return roots; } + public UnsupportedAttributePolicy getUnsupportedAttributePolicy() { + return unsupportedAttributePolicy; + } + + public void setUnsupportedAttributePolicy(UnsupportedAttributePolicy unsupportedAttributePolicy) { + this.unsupportedAttributePolicy = unsupportedAttributePolicy; + } + public String getUserName() { return userName; } @@ -227,7 +243,7 @@ public class NativeFileSystemView implements FileSystemView { public NativeSshFile createNativeSshFile(String name, File file, String userName) { name = deNormalizeSeparateChar(name); - if (isJava7 && !isWindows) { + if (isJava7) { return new NativeSshFileNio(this, name, file, userName); } else { return new NativeSshFile(this, name, file, userName); http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/97b38fb0/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeSshFile.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeSshFile.java b/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeSshFile.java index 0ece66c..d63d446 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeSshFile.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeSshFile.java @@ -27,13 +27,17 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.RandomAccessFile; import java.lang.reflect.Method; +import java.nio.channels.FileChannel; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.StringTokenizer; import org.apache.sshd.common.file.SshFile; @@ -640,8 +644,46 @@ public class NativeSshFile implements SshFile { } public void setAttributes(Map<Attribute, Object> attributes) throws IOException { + Set<Attribute> unsupported = new HashSet<Attribute>(); + for (Attribute attribute : attributes.keySet()) { + Object value = attributes.get(attribute); + switch (attribute) { + case Size: { + long newSize = (Long) value; + FileChannel outChan = new FileOutputStream(file, true).getChannel(); + outChan.truncate(newSize); + outChan.close(); + continue; + } + case LastModifiedTime: + setLastModified((Long) value); + break; + default: + unsupported.add(attribute); + break; + } + } + handleUnsupportedAttributes(unsupported); + } + + protected void handleUnsupportedAttributes(Collection<Attribute> attributes) { if (!attributes.isEmpty()) { - throw new UnsupportedOperationException(); + StringBuilder sb = new StringBuilder(); + for (Attribute attr : attributes) { + if (sb.length() > 0) { + sb.append(", "); + } + sb.append(attr.name()); + } + switch (nativeFileSystemView.getUnsupportedAttributePolicy()) { + case Ignore: + break; + case Warn: + LOG.warn("Unsupported attributes: " + sb.toString()); + break; + case ThrowException: + throw new UnsupportedOperationException("Unsupported attributes: " + sb.toString()); + } } } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/97b38fb0/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeSshFileNio.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeSshFileNio.java b/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeSshFileNio.java index c4cde42..1cfef6b 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeSshFileNio.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/file/nativefs/NativeSshFileNio.java @@ -58,27 +58,71 @@ public class NativeSshFileNio extends NativeSshFile { } public Map<Attribute, Object> getAttributes(boolean followLinks) throws IOException { - Map<String, Object> a = Files.readAttributes( - file.toPath(), - "unix:size,uid,owner,gid,group,isDirectory,isRegularFile,isSymbolicLink,permissions,creationTime,lastModifiedTime,lastAccessTime", - followLinks ? new LinkOption[0] : new LinkOption[] { LinkOption.NOFOLLOW_LINKS }); + String[] attrs = new String[] { "unix:*", "posix:*", "*" }; + Map<String, Object> a = null; + for (String attr : attrs) { + try { + a = Files.readAttributes( + file.toPath(), attr, + followLinks ? new LinkOption[0] : new LinkOption[]{LinkOption.NOFOLLOW_LINKS}); + break; + } catch (UnsupportedOperationException e) { + // Ignore + } + } + if (a == null) { + throw new IllegalStateException(); + } Map<Attribute, Object> map = new HashMap<Attribute, Object>(); map.put(Attribute.Size, a.get("size")); - map.put(Attribute.Uid, a.get("uid")); - map.put(Attribute.Owner, ((UserPrincipal) a.get("owner")).getName()); - map.put(Attribute.Gid, a.get("gid")); - map.put(Attribute.Group, ((GroupPrincipal) a.get("group")).getName()); + if (a.containsKey("uid")) { + map.put(Attribute.Uid, a.get("uid")); + } + if (a.containsKey("owner")) { + map.put(Attribute.Owner, ((UserPrincipal) a.get("owner")).getName()); + } else { + map.put(Attribute.Owner, userName); + } + if (a.containsKey("gid")) { + map.put(Attribute.Gid, a.get("gid")); + } + if (a.containsKey("group")) { + map.put(Attribute.Group, ((GroupPrincipal) a.get("group")).getName()); + } else { + map.put(Attribute.Group, userName); + } map.put(Attribute.IsDirectory, a.get("isDirectory")); map.put(Attribute.IsRegularFile, a.get("isRegularFile")); map.put(Attribute.IsSymbolicLink, a.get("isSymbolicLink")); map.put(Attribute.CreationTime, ((FileTime) a.get("creationTime")).toMillis()); map.put(Attribute.LastModifiedTime, ((FileTime) a.get("lastModifiedTime")).toMillis()); map.put(Attribute.LastAccessTime, ((FileTime) a.get("lastAccessTime")).toMillis()); - map.put(Attribute.Permissions, fromPerms((Set<PosixFilePermission>) a.get("permissions"))); + if (a.containsKey("permissions")) { + map.put(Attribute.Permissions, fromPerms((Set<PosixFilePermission>) a.get("permissions"))); + } else { + EnumSet<Permission> p = EnumSet.noneOf(Permission.class); + if (isReadable()) { + p.add(Permission.UserRead); + p.add(Permission.GroupRead); + p.add(Permission.OthersRead); + } + if (isWritable()) { + p.add(Permission.UserWrite); + p.add(Permission.GroupWrite); + p.add(Permission.OthersWrite); + } + if (isExecutable()) { + p.add(Permission.UserExecute); + p.add(Permission.GroupExecute); + p.add(Permission.OthersExecute); + } + map.put(Attribute.Permissions, p); + } return map; } public void setAttributes(Map<Attribute, Object> attributes) throws IOException { + Set<Attribute> unsupported = new HashSet<Attribute>(); for (Attribute attribute : attributes.keySet()) { String name = null; Object value = attributes.get(attribute); @@ -91,18 +135,23 @@ public class NativeSshFileNio extends NativeSshFile { continue; } case Uid: name = "unix:uid"; break; - case Owner: name = "unix:owner"; value = toUser((String) value); break; case Gid: name = "unix:gid"; break; - case Group: name = "unix:group"; value = toGroup((String) value); break; - case Permissions: name = "unix:permissions"; value = toPerms((EnumSet<Permission>) value); break; - case CreationTime: name = "unix:creationTime"; value = FileTime.fromMillis((Long) value); break; - case LastModifiedTime: name = "unix:lastModifiedTime"; value = FileTime.fromMillis((Long) value); break; - case LastAccessTime: name = "unix:lastAccessTime"; value = FileTime.fromMillis((Long) value); break; + case Owner: name = "posix:owner"; value = toUser((String) value); break; + case Group: name = "posix:group"; value = toGroup((String) value); break; + case Permissions: name = "posix:permissions"; value = toPerms((EnumSet<Permission>) value); break; + case CreationTime: name = "basic:creationTime"; value = FileTime.fromMillis((Long) value); break; + case LastModifiedTime: name = "basic:lastModifiedTime"; value = FileTime.fromMillis((Long) value); break; + case LastAccessTime: name = "basic:lastAccessTime"; value = FileTime.fromMillis((Long) value); break; } if (name != null && value != null) { - Files.setAttribute(file.toPath(), name, value, LinkOption.NOFOLLOW_LINKS); + try { + Files.setAttribute(file.toPath(), name, value, LinkOption.NOFOLLOW_LINKS); + } catch (UnsupportedOperationException e) { + unsupported.add(attribute); + } } } + handleUnsupportedAttributes(unsupported); } public String readSymbolicLink() throws IOException {
