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 2018/04/16 11:48:11 UTC
[24/30] mina-sshd git commit: [SSHD-815] Extract SFTP in its own
module
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
deleted file mode 100644
index ad6234c..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.common.subsystem.sftp;
-
-import java.util.Collections;
-import java.util.Map;
-
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.logging.LoggingUtils;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-@SuppressWarnings("PMD.AvoidUsingOctalValues")
-public final class SftpConstants {
- public static final String SFTP_SUBSYSTEM_NAME = "sftp";
-
- public static final int SSH_FXP_INIT = 1;
- public static final int SSH_FXP_VERSION = 2;
- public static final int SSH_FXP_OPEN = 3;
- public static final int SSH_FXP_CLOSE = 4;
- public static final int SSH_FXP_READ = 5;
- public static final int SSH_FXP_WRITE = 6;
- public static final int SSH_FXP_LSTAT = 7;
- public static final int SSH_FXP_FSTAT = 8;
- public static final int SSH_FXP_SETSTAT = 9;
- public static final int SSH_FXP_FSETSTAT = 10;
- public static final int SSH_FXP_OPENDIR = 11;
- public static final int SSH_FXP_READDIR = 12;
- public static final int SSH_FXP_REMOVE = 13;
- public static final int SSH_FXP_MKDIR = 14;
- public static final int SSH_FXP_RMDIR = 15;
- public static final int SSH_FXP_REALPATH = 16;
- public static final int SSH_FXP_STAT = 17;
- public static final int SSH_FXP_RENAME = 18;
- public static final int SSH_FXP_READLINK = 19;
- public static final int SSH_FXP_SYMLINK = 20; // v3 -> v5
- public static final int SSH_FXP_LINK = 21; // v6
- public static final int SSH_FXP_BLOCK = 22; // v6
- public static final int SSH_FXP_UNBLOCK = 23; // v6
- public static final int SSH_FXP_STATUS = 101;
- public static final int SSH_FXP_HANDLE = 102;
- public static final int SSH_FXP_DATA = 103;
- public static final int SSH_FXP_NAME = 104;
- public static final int SSH_FXP_ATTRS = 105;
- public static final int SSH_FXP_EXTENDED = 200;
- public static final int SSH_FXP_EXTENDED_REPLY = 201;
-
- public static final int SSH_FX_OK = 0;
- public static final int SSH_FX_EOF = 1;
- public static final int SSH_FX_NO_SUCH_FILE = 2;
- public static final int SSH_FX_PERMISSION_DENIED = 3;
- public static final int SSH_FX_FAILURE = 4;
- public static final int SSH_FX_BAD_MESSAGE = 5;
- public static final int SSH_FX_NO_CONNECTION = 6;
- public static final int SSH_FX_CONNECTION_LOST = 7;
- public static final int SSH_FX_OP_UNSUPPORTED = 8;
- public static final int SSH_FX_INVALID_HANDLE = 9;
- public static final int SSH_FX_NO_SUCH_PATH = 10;
- public static final int SSH_FX_FILE_ALREADY_EXISTS = 11;
- public static final int SSH_FX_WRITE_PROTECT = 12;
- public static final int SSH_FX_NO_MEDIA = 13;
- public static final int SSH_FX_NO_SPACE_ON_FILESYSTEM = 14;
- public static final int SSH_FX_QUOTA_EXCEEDED = 15;
- public static final int SSH_FX_UNKNOWN_PRINCIPAL = 16;
- public static final int SSH_FX_LOCK_CONFLICT = 17;
- public static final int SSH_FX_DIR_NOT_EMPTY = 18;
- public static final int SSH_FX_NOT_A_DIRECTORY = 19;
- public static final int SSH_FX_INVALID_FILENAME = 20;
- public static final int SSH_FX_LINK_LOOP = 21;
- public static final int SSH_FX_CANNOT_DELETE = 22;
- public static final int SSH_FX_INVALID_PARAMETER = 23;
- public static final int SSH_FX_FILE_IS_A_DIRECTORY = 24;
- public static final int SSH_FX_BYTE_RANGE_LOCK_CONFLICT = 25;
- public static final int SSH_FX_BYTE_RANGE_LOCK_REFUSED = 26;
- public static final int SSH_FX_DELETE_PENDING = 27;
- public static final int SSH_FX_FILE_CORRUPT = 28;
- public static final int SSH_FX_OWNER_INVALID = 29;
- public static final int SSH_FX_GROUP_INVALID = 30;
- public static final int SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK = 31;
-
- public static final int SSH_FILEXFER_ATTR_SIZE = 0x00000001;
- public static final int SSH_FILEXFER_ATTR_UIDGID = 0x00000002;
- public static final int SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004;
- public static final int SSH_FILEXFER_ATTR_ACMODTIME = 0x00000008; // v3 naming convention
- public static final int SSH_FILEXFER_ATTR_ACCESSTIME = 0x00000008; // v4
- public static final int SSH_FILEXFER_ATTR_CREATETIME = 0x00000010; // v4
- public static final int SSH_FILEXFER_ATTR_MODIFYTIME = 0x00000020; // v4
- public static final int SSH_FILEXFER_ATTR_ACL = 0x00000040; // v4
- public static final int SSH_FILEXFER_ATTR_OWNERGROUP = 0x00000080; // v4
- public static final int SSH_FILEXFER_ATTR_SUBSECOND_TIMES = 0x00000100; // v5
- public static final int SSH_FILEXFER_ATTR_BITS = 0x00000200; // v5
- public static final int SSH_FILEXFER_ATTR_ALLOCATION_SIZE = 0x00000400; // v6
- public static final int SSH_FILEXFER_ATTR_TEXT_HINT = 0x00000800; // v6
- public static final int SSH_FILEXFER_ATTR_MIME_TYPE = 0x00001000; // v6
- public static final int SSH_FILEXFER_ATTR_LINK_COUNT = 0x00002000; // v6
- public static final int SSH_FILEXFER_ATTR_UNTRANSLATED_NAME = 0x00004000; // v6
- public static final int SSH_FILEXFER_ATTR_CTIME = 0x00008000; // v6
- public static final int SSH_FILEXFER_ATTR_EXTENDED = 0x80000000;
-
- public static final int SSH_FILEXFER_ATTR_ALL = 0x0000FFFF; // All attributes
-
- public static final int SSH_FILEXFER_ATTR_FLAGS_READONLY = 0x00000001;
- public static final int SSH_FILEXFER_ATTR_FLAGS_SYSTEM = 0x00000002;
- public static final int SSH_FILEXFER_ATTR_FLAGS_HIDDEN = 0x00000004;
- public static final int SSH_FILEXFER_ATTR_FLAGS_CASE_INSENSITIVE = 0x00000008;
- public static final int SSH_FILEXFER_ATTR_FLAGS_ARCHIVE = 0x00000010;
- public static final int SSH_FILEXFER_ATTR_FLAGS_ENCRYPTED = 0x00000020;
- public static final int SSH_FILEXFER_ATTR_FLAGS_COMPRESSED = 0x00000040;
- public static final int SSH_FILEXFER_ATTR_FLAGS_SPARSE = 0x00000080;
- public static final int SSH_FILEXFER_ATTR_FLAGS_APPEND_ONLY = 0x00000100;
- public static final int SSH_FILEXFER_ATTR_FLAGS_IMMUTABLE = 0x00000200;
- public static final int SSH_FILEXFER_ATTR_FLAGS_SYNC = 0x00000400;
-
- 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_READ = 0x00000001;
- public static final int SSH_FXF_WRITE = 0x00000002;
- public static final int SSH_FXF_APPEND = 0x00000004;
- public static final int SSH_FXF_CREAT = 0x00000008;
- public static final int SSH_FXF_TRUNC = 0x00000010;
- public static final int SSH_FXF_EXCL = 0x00000020;
- public static final int SSH_FXF_TEXT = 0x00000040;
-
- 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;
- public static final int SSH_FXF_OPEN_EXISTING = 0x00000002;
- public static final int SSH_FXF_OPEN_OR_CREATE = 0x00000003;
- public static final int SSH_FXF_TRUNCATE_EXISTING = 0x00000004;
- public static final int SSH_FXF_APPEND_DATA = 0x00000008;
- public static final int SSH_FXF_APPEND_DATA_ATOMIC = 0x00000010;
- public static final int SSH_FXF_TEXT_MODE = 0x00000020;
- public static final int SSH_FXF_READ_LOCK = 0x00000040;
- public static final int SSH_FXF_WRITE_LOCK = 0x00000080;
- public static final int SSH_FXF_DELETE_LOCK = 0x00000100;
- public static final int SSH_FXF_BLOCK_ADVISORY = 0x00000200;
- public static final int SSH_FXF_NOFOLLOW = 0x00000400;
- public static final int SSH_FXF_DELETE_ON_CLOSE = 0x00000800;
- public static final int SSH_FXF_ACCESS_AUDIT_ALARM_INFO = 0x00001000;
- public static final int SSH_FXF_ACCESS_BACKUP = 0x00002000;
- public static final int SSH_FXF_BACKUP_STREAM = 0x00004000;
- public static final int SSH_FXF_OVERRIDE_OWNER = 0x00008000;
-
- public static final int SSH_FXP_RENAME_OVERWRITE = 0x00000001;
- public static final int SSH_FXP_RENAME_ATOMIC = 0x00000002;
- public static final int SSH_FXP_RENAME_NATIVE = 0x00000004;
-
- public static final int SSH_FXP_REALPATH_NO_CHECK = 0x00000001;
- public static final int SSH_FXP_REALPATH_STAT_IF = 0x00000002;
- public static final int SSH_FXP_REALPATH_STAT_ALWAYS = 0x00000003;
-
- public static final int SSH_FXF_RENAME_OVERWRITE = 0x00000001;
- public static final int SSH_FXF_RENAME_ATOMIC = 0x00000002;
- public static final int SSH_FXF_RENAME_NATIVE = 0x00000004;
-
- public static final int SFX_ACL_CONTROL_INCLUDED = 0x00000001;
- public static final int SFX_ACL_CONTROL_PRESENT = 0x00000002;
- public static final int SFX_ACL_CONTROL_INHERITED = 0x00000004;
- public static final int SFX_ACL_AUDIT_ALARM_INCLUDED = 0x00000010;
- public static final int SFX_ACL_AUDIT_ALARM_INHERITED = 0x00000020;
-
- public static final int ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000;
- public static final int ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001;
- public static final int ACE4_SYSTEM_AUDIT_ACE_TYPE = 0x00000002;
- public static final int ACE4_SYSTEM_ALARM_ACE_TYPE = 0x00000003;
-
- public static final int ACE4_FILE_INHERIT_ACE = 0x00000001;
- public static final int ACE4_DIRECTORY_INHERIT_ACE = 0x00000002;
- public static final int ACE4_NO_PROPAGATE_INHERIT_ACE = 0x00000004;
- public static final int ACE4_INHERIT_ONLY_ACE = 0x00000008;
- public static final int ACE4_SUCCESSFUL_ACCESS_ACE_FLAG = 0x00000010;
- public static final int ACE4_FAILED_ACCESS_ACE_FLAG = 0x00000020;
- public static final int ACE4_IDENTIFIER_GROUP = 0x00000040;
-
- public static final int ACE4_READ_DATA = 0x00000001;
- public static final int ACE4_LIST_DIRECTORY = 0x00000001;
- public static final int ACE4_WRITE_DATA = 0x00000002;
- public static final int ACE4_ADD_FILE = 0x00000002;
- public static final int ACE4_APPEND_DATA = 0x00000004;
- public static final int ACE4_ADD_SUBDIRECTORY = 0x00000004;
- public static final int ACE4_READ_NAMED_ATTRS = 0x00000008;
- public static final int ACE4_WRITE_NAMED_ATTRS = 0x00000010;
- public static final int ACE4_EXECUTE = 0x00000020;
- public static final int ACE4_DELETE_CHILD = 0x00000040;
- public static final int ACE4_READ_ATTRIBUTES = 0x00000080;
- public static final int ACE4_WRITE_ATTRIBUTES = 0x00000100;
- public static final int ACE4_DELETE = 0x00010000;
- public static final int ACE4_READ_ACL = 0x00020000;
- public static final int ACE4_WRITE_ACL = 0x00040000;
- public static final int ACE4_WRITE_OWNER = 0x00080000;
- public static final int ACE4_SYNCHRONIZE = 0x00100000;
-
- public static final int S_IFMT = 0170000; // bitmask for the file type bitfields
- public static final int S_IFSOCK = 0140000; // socket
- public static final int S_IFLNK = 0120000; // symbolic link
- public static final int S_IFREG = 0100000; // regular file
- public static final int S_IFBLK = 0060000; // block device
- public static final int S_IFDIR = 0040000; // directory
- public static final int S_IFCHR = 0020000; // character device
- public static final int S_IFIFO = 0010000; // fifo
- public static final int S_ISUID = 0004000; // set UID bit
- public static final int S_ISGID = 0002000; // set GID bit
- public static final int S_ISVTX = 0001000; // sticky bit
- public static final int S_IRUSR = 0000400;
- public static final int S_IWUSR = 0000200;
- public static final int S_IXUSR = 0000100;
- public static final int S_IRGRP = 0000040;
- public static final int S_IWGRP = 0000020;
- public static final int S_IXGRP = 0000010;
- public static final int S_IROTH = 0000004;
- public static final int S_IWOTH = 0000002;
- public static final int S_IXOTH = 0000001;
-
- public static final int SFTP_V3 = 3;
- public static final int SFTP_V4 = 4;
- public static final int SFTP_V5 = 5;
- public static final int SFTP_V6 = 6;
-
- // (Some) names of known extensions
- public static final String EXT_VERSIONS = "versions";
- public static final String EXT_NEWLINE = "newline";
- public static final String EXT_VENDOR_ID = "vendor-id";
- public static final String EXT_SUPPORTED = "supported";
- public static final String EXT_SUPPORTED2 = "supported2";
- public static final String EXT_TEXT_SEEK = "text-seek";
- public static final String EXT_VERSION_SELECT = "version-select";
- public static final String EXT_COPY_FILE = "copy-file";
-
- public static final String EXT_MD5_HASH = "md5-hash";
- public static final String EXT_MD5_HASH_HANDLE = "md5-hash-handle";
- public static final int MD5_QUICK_HASH_SIZE = 2048;
-
- public static final String EXT_CHECK_FILE_HANDLE = "check-file-handle";
- public static final String EXT_CHECK_FILE_NAME = "check-file-name";
- public static final int MIN_CHKFILE_BLOCKSIZE = 256;
-
- public static final String EXT_CHECK_FILE = "check-file";
- public static final String EXT_COPY_DATA = "copy-data";
- public static final String EXT_SPACE_AVAILABLE = "space-available";
-
- // see https://tools.ietf.org/html/draft-ietf-secsh-filexfer-11 section 5.4
- public static final String EXT_ACL_SUPPORTED = "acl-supported";
- public static final int SSH_ACL_CAP_ALLOW = 0x00000001;
- public static final int SSH_ACL_CAP_DENY = 0x00000002;
- public static final int SSH_ACL_CAP_AUDIT = 0x00000004;
- public static final int SSH_ACL_CAP_ALARM = 0x00000008;
- public static final int SSH_ACL_CAP_INHERIT_ACCESS = 0x00000010;
- public static final int SSH_ACL_CAP_INHERIT_AUDIT_ALARM = 0x00000020;
-
- private SftpConstants() {
- throw new UnsupportedOperationException("No instance");
- }
-
- private static class LazyCommandNameHolder {
- private static final Map<Integer, String> NAMES_MAP =
- Collections.unmodifiableMap(
- LoggingUtils.generateMnemonicMap(SftpConstants.class, f -> {
- String name = f.getName();
- return name.startsWith("SSH_FXP_")
- // exclude the rename modes which are not opcodes
- && (!name.startsWith("SSH_FXP_RENAME_"))
- // exclude the realpath modes wich are not opcodes
- && (!name.startsWith("SSH_FXP_REALPATH_"));
- }));
- }
-
- /**
- * Converts a command value to a user-friendly name
- *
- * @param cmd The command value
- * @return The user-friendly name - if not one of the defined {@code SSH_FXP_XXX}
- * values then returns the string representation of the command's value
- */
- public static String getCommandMessageName(int cmd) {
- @SuppressWarnings("synthetic-access")
- String name = LazyCommandNameHolder.NAMES_MAP.get(cmd);
- if (GenericUtils.isEmpty(name)) {
- return Integer.toString(cmd);
- } else {
- return name;
- }
- }
-
- private static class LazyStatusNameHolder {
- private static final Map<Integer, String> STATUS_MAP =
- Collections.unmodifiableMap(LoggingUtils.generateMnemonicMap(SftpConstants.class, "SSH_FX_"));
- }
-
- /**
- * Converts a return status value to a user-friendly name
- *
- * @param status The status value
- * @return The user-friendly name - if not one of the defined {@code SSH_FX_XXX}
- * values then returns the string representation of the status value
- */
- public static String getStatusName(int status) {
- @SuppressWarnings("synthetic-access")
- String name = LazyStatusNameHolder.STATUS_MAP.get(status);
- if (GenericUtils.isEmpty(name)) {
- return Integer.toString(status);
- } else {
- return name;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpException.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpException.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpException.java
deleted file mode 100644
index b7fd157..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpException.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.common.subsystem.sftp;
-
-import java.io.IOException;
-
-/**
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
- */
-public class SftpException extends IOException {
- private static final long serialVersionUID = 8096963562429466995L;
- private final int status;
-
- public SftpException(int status, String msg) {
- super(msg);
- this.status = status;
- }
-
- public int getStatus() {
- return status;
- }
-
- @Override
- public String toString() {
- return "SFTP error (" + SftpConstants.getStatusName(getStatus()) + "): " + getMessage();
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpHelper.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpHelper.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpHelper.java
deleted file mode 100644
index 5f83818..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpHelper.java
+++ /dev/null
@@ -1,1114 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.common.subsystem.sftp;
-
-import java.io.EOFException;
-import java.io.FileNotFoundException;
-import java.net.UnknownServiceException;
-import java.nio.channels.OverlappingFileLockException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.AccessDeniedException;
-import java.nio.file.DirectoryNotEmptyException;
-import java.nio.file.FileAlreadyExistsException;
-import java.nio.file.FileSystemLoopException;
-import java.nio.file.InvalidPathException;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.NotDirectoryException;
-import java.nio.file.attribute.AclEntry;
-import java.nio.file.attribute.AclEntryFlag;
-import java.nio.file.attribute.AclEntryPermission;
-import java.nio.file.attribute.AclEntryType;
-import java.nio.file.attribute.FileTime;
-import java.nio.file.attribute.PosixFilePermission;
-import java.nio.file.attribute.PosixFilePermissions;
-import java.nio.file.attribute.UserPrincipal;
-import java.nio.file.attribute.UserPrincipalNotFoundException;
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Map;
-import java.util.NavigableMap;
-import java.util.Objects;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.sshd.common.PropertyResolver;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.OsUtils;
-import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.BufferUtils;
-import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
-import org.apache.sshd.server.subsystem.sftp.DefaultGroupPrincipal;
-import org.apache.sshd.server.subsystem.sftp.InvalidHandleException;
-import org.apache.sshd.server.subsystem.sftp.UnixDateFormat;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public final class SftpHelper {
- /**
- * Used to control whether to append the end-of-list indicator for
- * SSH_FXP_NAME responses via {@link #indicateEndOfNamesList(Buffer, int, PropertyResolver, Boolean)}
- * call, as indicated by <A HREF="https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.4">SFTP v6 - section 9.4</A>
- */
- public static final String APPEND_END_OF_LIST_INDICATOR = "sftp-append-eol-indicator";
-
- /**
- * Default value for {@link #APPEND_END_OF_LIST_INDICATOR} if none configured
- */
- public static final boolean DEFAULT_APPEND_END_OF_LIST_INDICATOR = true;
-
- public static final NavigableMap<Integer, String> DEFAULT_SUBSTATUS_MESSAGE =
- Collections.unmodifiableNavigableMap(new TreeMap<Integer, String>(Comparator.naturalOrder()) {
- // Not serializing it
- private static final long serialVersionUID = 1L;
-
- {
- put(SftpConstants.SSH_FX_OK, "Success");
- put(SftpConstants.SSH_FX_EOF, "End of file");
- put(SftpConstants.SSH_FX_NO_SUCH_FILE, "No such file or directory");
- put(SftpConstants.SSH_FX_PERMISSION_DENIED, "Permission denied");
- put(SftpConstants.SSH_FX_FAILURE, "General failure");
- put(SftpConstants.SSH_FX_BAD_MESSAGE, "Bad message data");
- put(SftpConstants.SSH_FX_NO_CONNECTION, "No connection to server");
- put(SftpConstants.SSH_FX_CONNECTION_LOST, "Connection lost");
- put(SftpConstants.SSH_FX_OP_UNSUPPORTED, "Unsupported operation requested");
- put(SftpConstants.SSH_FX_INVALID_HANDLE, "Invalid handle value");
- put(SftpConstants.SSH_FX_NO_SUCH_PATH, "No such path");
- put(SftpConstants.SSH_FX_FILE_ALREADY_EXISTS, "File/Directory already exists");
- put(SftpConstants.SSH_FX_WRITE_PROTECT, "File/Directory is write-protected");
- put(SftpConstants.SSH_FX_NO_MEDIA, "No such meadia");
- put(SftpConstants.SSH_FX_NO_SPACE_ON_FILESYSTEM, "No space left on device");
- put(SftpConstants.SSH_FX_QUOTA_EXCEEDED, "Quota exceeded");
- put(SftpConstants.SSH_FX_UNKNOWN_PRINCIPAL, "Unknown user/group");
- put(SftpConstants.SSH_FX_LOCK_CONFLICT, "Lock conflict");
- put(SftpConstants.SSH_FX_DIR_NOT_EMPTY, "Directory not empty");
- put(SftpConstants.SSH_FX_NOT_A_DIRECTORY, "Accessed location is not a directory");
- put(SftpConstants.SSH_FX_INVALID_FILENAME, "Invalid filename");
- put(SftpConstants.SSH_FX_LINK_LOOP, "Link loop");
- put(SftpConstants.SSH_FX_CANNOT_DELETE, "Cannot remove");
- put(SftpConstants.SSH_FX_INVALID_PARAMETER, "Invalid parameter");
- put(SftpConstants.SSH_FX_FILE_IS_A_DIRECTORY, "Accessed location is a directory");
- put(SftpConstants.SSH_FX_BYTE_RANGE_LOCK_CONFLICT, "Range lock conflict");
- put(SftpConstants.SSH_FX_BYTE_RANGE_LOCK_REFUSED, "Range lock refused");
- put(SftpConstants.SSH_FX_DELETE_PENDING, "Delete pending");
- put(SftpConstants.SSH_FX_FILE_CORRUPT, "Corrupted file/directory");
- put(SftpConstants.SSH_FX_OWNER_INVALID, "Invalid file/directory owner");
- put(SftpConstants.SSH_FX_GROUP_INVALID, "Invalid file/directory group");
- put(SftpConstants.SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK, "No matching byte range lock");
- }
- });
-
- private SftpHelper() {
- throw new UnsupportedOperationException("No instance allowed");
- }
-
- /**
- * Retrieves the end-of-file indicator for {@code SSH_FXP_DATA} responses, provided
- * the version is at least 6, and the buffer has enough available data
- *
- * @param buffer The {@link Buffer} to retrieve the data from
- * @param version The SFTP version being used
- * @return The indicator value - {@code null} if none retrieved
- * @see <A HREF="https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.3">SFTP v6 - section 9.3</A>
- */
- public static Boolean getEndOfFileIndicatorValue(Buffer buffer, int version) {
- return (version < SftpConstants.SFTP_V6) || (buffer.available() < 1) ? null : buffer.getBoolean();
- }
-
- /**
- * Retrieves the end-of-list indicator for {@code SSH_FXP_NAME} responses, provided
- * the version is at least 6, and the buffer has enough available data
- *
- * @param buffer The {@link Buffer} to retrieve the data from
- * @param version The SFTP version being used
- * @return The indicator value - {@code null} if none retrieved
- * @see <A HREF="https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.4">SFTP v6 - section 9.4</A>
- * @see #indicateEndOfNamesList(Buffer, int, PropertyResolver, Boolean)
- */
- public static Boolean getEndOfListIndicatorValue(Buffer buffer, int version) {
- return (version < SftpConstants.SFTP_V6) || (buffer.available() < 1) ? null : buffer.getBoolean();
- }
-
- /**
- * Appends the end-of-list={@code TRUE} indicator for {@code SSH_FXP_NAME} responses, provided
- * the version is at least 6 and the feature is enabled
- *
- * @param buffer The {@link Buffer} to append the indicator
- * @param version The SFTP version being used
- * @param resolver The {@link PropertyResolver} to query whether to enable the feature
- * @return The actual indicator value used - {@code null} if none appended
- * @see #indicateEndOfNamesList(Buffer, int, PropertyResolver, Boolean)
- */
- public static Boolean indicateEndOfNamesList(Buffer buffer, int version, PropertyResolver resolver) {
- return indicateEndOfNamesList(buffer, version, resolver, Boolean.TRUE);
- }
-
- /**
- * Appends the end-of-list indicator for {@code SSH_FXP_NAME} responses, provided the version
- * is at least 6, the feature is enabled and the indicator value is not {@code null}
- *
- * @param buffer The {@link Buffer} to append the indicator
- * @param version The SFTP version being used
- * @param resolver The {@link PropertyResolver} to query whether to enable the feature
- * @param indicatorValue The indicator value - {@code null} means don't append the indicator
- * @return The actual indicator value used - {@code null} if none appended
- * @see <A HREF="https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.4">SFTP v6 - section 9.4</A>
- * @see #APPEND_END_OF_LIST_INDICATOR
- * @see #DEFAULT_APPEND_END_OF_LIST_INDICATOR
- */
- public static Boolean indicateEndOfNamesList(Buffer buffer, int version, PropertyResolver resolver, Boolean indicatorValue) {
- if ((version < SftpConstants.SFTP_V6) || (indicatorValue == null)) {
- return null;
- }
-
- if (!resolver.getBooleanProperty(APPEND_END_OF_LIST_INDICATOR, DEFAULT_APPEND_END_OF_LIST_INDICATOR)) {
- return null;
- }
-
- buffer.putBoolean(indicatorValue);
- return indicatorValue;
- }
-
- /**
- * Writes a file / folder's attributes to a buffer
- *
- * @param <B> Type of {@link Buffer} being updated
- * @param buffer The target buffer instance
- * @param version The output encoding version
- * @param attributes The {@link Map} of attributes
- * @return The updated buffer
- * @see #writeAttrsV3(Buffer, int, Map)
- * @see #writeAttrsV4(Buffer, int, Map)
- */
- public static <B extends Buffer> B writeAttrs(B buffer, int version, Map<String, ?> attributes) {
- if (version == SftpConstants.SFTP_V3) {
- return writeAttrsV3(buffer, version, attributes);
- } else if (version >= SftpConstants.SFTP_V4) {
- return writeAttrsV4(buffer, version, attributes);
- } else {
- throw new IllegalStateException("Unsupported SFTP version: " + version);
- }
- }
-
- /**
- * Writes the retrieved file / directory attributes in V3 format
- *
- * @param <B> Type of {@link Buffer} being updated
- * @param buffer The target buffer instance
- * @param version The actual version - must be {@link SftpConstants#SFTP_V3}
- * @param attributes The {@link Map} of attributes
- * @return The updated buffer
- */
- public static <B extends Buffer> B writeAttrsV3(B buffer, int version, Map<String, ?> attributes) {
- ValidateUtils.checkTrue(version == SftpConstants.SFTP_V3, "Illegal version: %d", version);
-
- 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");
- Map<?, ?> extensions = (Map<?, ?>) attributes.get("extended");
- int flags = ((isReg || isLnk) && (size != null) ? SftpConstants.SSH_FILEXFER_ATTR_SIZE : 0)
- | (attributes.containsKey("uid") && attributes.containsKey("gid") ? SftpConstants.SSH_FILEXFER_ATTR_UIDGID : 0)
- | ((perms != null) ? SftpConstants.SSH_FILEXFER_ATTR_PERMISSIONS : 0)
- | (((lastModifiedTime != null) && (lastAccessTime != null)) ? SftpConstants.SSH_FILEXFER_ATTR_ACMODTIME : 0)
- | ((extensions != null) ? SftpConstants.SSH_FILEXFER_ATTR_EXTENDED : 0);
- buffer.putInt(flags);
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_SIZE) != 0) {
- buffer.putLong(size.longValue());
- }
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_UIDGID) != 0) {
- buffer.putInt(((Number) attributes.get("uid")).intValue());
- buffer.putInt(((Number) attributes.get("gid")).intValue());
- }
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_PERMISSIONS) != 0) {
- buffer.putInt(attributesToPermissions(isReg, isDir, isLnk, perms));
- }
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_ACMODTIME) != 0) {
- buffer = writeTime(buffer, version, flags, lastAccessTime);
- buffer = writeTime(buffer, version, flags, lastModifiedTime);
- }
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_EXTENDED) != 0) {
- buffer = writeExtensions(buffer, extensions);
- }
-
- return buffer;
- }
-
- /**
- * Writes the retrieved file / directory attributes in V4+ format
- *
- * @param <B> Type of {@link Buffer} being updated
- * @param buffer The target buffer instance
- * @param version The actual version - must be at least {@link SftpConstants#SFTP_V4}
- * @param attributes The {@link Map} of attributes
- * @return The updated buffer
- */
- public static <B extends Buffer> B writeAttrsV4(B buffer, int version, Map<String, ?> attributes) {
- ValidateUtils.checkTrue(version >= SftpConstants.SFTP_V4, "Illegal version: %d", version);
-
- 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");
- FileTime creationTime = (FileTime) attributes.get("creationTime");
- @SuppressWarnings("unchecked")
- Collection<AclEntry> acl = (Collection<AclEntry>) attributes.get("acl");
- Map<?, ?> extensions = (Map<?, ?>) attributes.get("extended");
- int flags = (((isReg || isLnk) && (size != null)) ? SftpConstants.SSH_FILEXFER_ATTR_SIZE : 0)
- | ((attributes.containsKey("owner") && attributes.containsKey("group")) ? SftpConstants.SSH_FILEXFER_ATTR_OWNERGROUP : 0)
- | ((perms != null) ? SftpConstants.SSH_FILEXFER_ATTR_PERMISSIONS : 0)
- | ((lastModifiedTime != null) ? SftpConstants.SSH_FILEXFER_ATTR_MODIFYTIME : 0)
- | ((creationTime != null) ? SftpConstants.SSH_FILEXFER_ATTR_CREATETIME : 0)
- | ((lastAccessTime != null) ? SftpConstants.SSH_FILEXFER_ATTR_ACCESSTIME : 0)
- | ((acl != null) ? SftpConstants.SSH_FILEXFER_ATTR_ACL : 0)
- | ((extensions != null) ? SftpConstants.SSH_FILEXFER_ATTR_EXTENDED : 0);
- buffer.putInt(flags);
- buffer.putByte((byte) (isReg ? SftpConstants.SSH_FILEXFER_TYPE_REGULAR
- : isDir ? SftpConstants.SSH_FILEXFER_TYPE_DIRECTORY
- : isLnk ? SftpConstants.SSH_FILEXFER_TYPE_SYMLINK
- : SftpConstants.SSH_FILEXFER_TYPE_UNKNOWN));
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_SIZE) != 0) {
- buffer.putLong(size.longValue());
- }
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_OWNERGROUP) != 0) {
- buffer.putString(Objects.toString(attributes.get("owner"), SftpUniversalOwnerAndGroup.Owner.getName()));
- buffer.putString(Objects.toString(attributes.get("group"), SftpUniversalOwnerAndGroup.Group.getName()));
- }
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_PERMISSIONS) != 0) {
- buffer.putInt(attributesToPermissions(isReg, isDir, isLnk, perms));
- }
-
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_ACCESSTIME) != 0) {
- buffer = writeTime(buffer, version, flags, lastAccessTime);
- }
-
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_CREATETIME) != 0) {
- buffer = writeTime(buffer, version, flags, lastAccessTime);
- }
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_MODIFYTIME) != 0) {
- buffer = writeTime(buffer, version, flags, lastModifiedTime);
- }
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_ACL) != 0) {
- buffer = writeACLs(buffer, version, acl);
- }
- // TODO: ctime
- // TODO: bits
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_EXTENDED) != 0) {
- buffer = writeExtensions(buffer, extensions);
- }
-
- return buffer;
- }
-
- /**
- * @param bool The {@link Boolean} value
- * @return {@code true} it the argument is non-{@code null} and
- * its {@link Boolean#booleanValue()} is {@code true}
- */
- public static boolean getBool(Boolean bool) {
- return bool != null && bool;
- }
-
- /**
- * Converts a file / folder's attributes into a mask
- *
- * @param isReg {@code true} if this is a normal file
- * @param isDir {@code true} if this is a directory
- * @param isLnk {@code true} if this is a symbolic link
- * @param perms The file / folder's access {@link PosixFilePermission}s
- * @return A mask encoding the file / folder's attributes
- */
- public static int attributesToPermissions(boolean isReg, boolean isDir, boolean isLnk, Collection<PosixFilePermission> perms) {
- int pf = 0;
- if (perms != null) {
- for (PosixFilePermission p : perms) {
- switch (p) {
- case OWNER_READ:
- pf |= SftpConstants.S_IRUSR;
- break;
- case OWNER_WRITE:
- pf |= SftpConstants.S_IWUSR;
- break;
- case OWNER_EXECUTE:
- pf |= SftpConstants.S_IXUSR;
- break;
- case GROUP_READ:
- pf |= SftpConstants.S_IRGRP;
- break;
- case GROUP_WRITE:
- pf |= SftpConstants.S_IWGRP;
- break;
- case GROUP_EXECUTE:
- pf |= SftpConstants.S_IXGRP;
- break;
- case OTHERS_READ:
- pf |= SftpConstants.S_IROTH;
- break;
- case OTHERS_WRITE:
- pf |= SftpConstants.S_IWOTH;
- break;
- case OTHERS_EXECUTE:
- pf |= SftpConstants.S_IXOTH;
- break;
- default: // ignored
- }
- }
- }
- pf |= isReg ? SftpConstants.S_IFREG : 0;
- pf |= isDir ? SftpConstants.S_IFDIR : 0;
- pf |= isLnk ? SftpConstants.S_IFLNK : 0;
- return pf;
- }
-
- /**
- * Converts a POSIX permissions mask to a file type value
- *
- * @param perms The POSIX permissions mask
- * @return The file type - see {@code SSH_FILEXFER_TYPE_xxx} values
- */
- public static int permissionsToFileType(int perms) {
- if ((SftpConstants.S_IFLNK & perms) == SftpConstants.S_IFLNK) {
- return SftpConstants.SSH_FILEXFER_TYPE_SYMLINK;
- } else if ((SftpConstants.S_IFREG & perms) == SftpConstants.S_IFREG) {
- return SftpConstants.SSH_FILEXFER_TYPE_REGULAR;
- } else if ((SftpConstants.S_IFDIR & perms) == SftpConstants.S_IFDIR) {
- return SftpConstants.SSH_FILEXFER_TYPE_DIRECTORY;
- } else if ((SftpConstants.S_IFSOCK & perms) == SftpConstants.S_IFSOCK) {
- return SftpConstants.SSH_FILEXFER_TYPE_SOCKET;
- } else if ((SftpConstants.S_IFBLK & perms) == SftpConstants.S_IFBLK) {
- return SftpConstants.SSH_FILEXFER_TYPE_BLOCK_DEVICE;
- } else if ((SftpConstants.S_IFCHR & perms) == SftpConstants.S_IFCHR) {
- return SftpConstants.SSH_FILEXFER_TYPE_CHAR_DEVICE;
- } else if ((SftpConstants.S_IFIFO & perms) == SftpConstants.S_IFIFO) {
- return SftpConstants.SSH_FILEXFER_TYPE_FIFO;
- } else {
- return SftpConstants.SSH_FILEXFER_TYPE_UNKNOWN;
- }
- }
-
- /**
- * Converts a file type into a POSIX permission mask value
-
- * @param type File type - see {@code SSH_FILEXFER_TYPE_xxx} values
- * @return The matching POSIX permission mask value
- */
- public static int fileTypeToPermission(int type) {
- switch (type) {
- case SftpConstants.SSH_FILEXFER_TYPE_REGULAR:
- return SftpConstants.S_IFREG;
- case SftpConstants.SSH_FILEXFER_TYPE_DIRECTORY:
- return SftpConstants.S_IFDIR;
- case SftpConstants.SSH_FILEXFER_TYPE_SYMLINK:
- return SftpConstants.S_IFLNK;
- case SftpConstants.SSH_FILEXFER_TYPE_SOCKET:
- return SftpConstants.S_IFSOCK;
- case SftpConstants.SSH_FILEXFER_TYPE_BLOCK_DEVICE:
- return SftpConstants.S_IFBLK;
- case SftpConstants.SSH_FILEXFER_TYPE_CHAR_DEVICE:
- return SftpConstants.S_IFCHR;
- case SftpConstants.SSH_FILEXFER_TYPE_FIFO:
- return SftpConstants.S_IFIFO;
- default:
- return 0;
- }
- }
-
- /**
- * Translates a mask of permissions into its enumeration values equivalents
- *
- * @param perms The permissions mask
- * @return A {@link Set} of the equivalent {@link PosixFilePermission}s
- */
- public static Set<PosixFilePermission> permissionsToAttributes(int perms) {
- Set<PosixFilePermission> p = EnumSet.noneOf(PosixFilePermission.class);
- if ((perms & SftpConstants.S_IRUSR) != 0) {
- p.add(PosixFilePermission.OWNER_READ);
- }
- if ((perms & SftpConstants.S_IWUSR) != 0) {
- p.add(PosixFilePermission.OWNER_WRITE);
- }
- if ((perms & SftpConstants.S_IXUSR) != 0) {
- p.add(PosixFilePermission.OWNER_EXECUTE);
- }
- if ((perms & SftpConstants.S_IRGRP) != 0) {
- p.add(PosixFilePermission.GROUP_READ);
- }
- if ((perms & SftpConstants.S_IWGRP) != 0) {
- p.add(PosixFilePermission.GROUP_WRITE);
- }
- if ((perms & SftpConstants.S_IXGRP) != 0) {
- p.add(PosixFilePermission.GROUP_EXECUTE);
- }
- if ((perms & SftpConstants.S_IROTH) != 0) {
- p.add(PosixFilePermission.OTHERS_READ);
- }
- if ((perms & SftpConstants.S_IWOTH) != 0) {
- p.add(PosixFilePermission.OTHERS_WRITE);
- }
- if ((perms & SftpConstants.S_IXOTH) != 0) {
- p.add(PosixFilePermission.OTHERS_EXECUTE);
- }
- return p;
- }
-
- /**
- * Returns the most adequate sub-status for the provided exception
- *
- * @param t The thrown {@link Throwable}
- * @return The matching sub-status
- */
- @SuppressWarnings("checkstyle:ReturnCount")
- public static int resolveSubstatus(Throwable t) {
- if ((t instanceof NoSuchFileException) || (t instanceof FileNotFoundException)) {
- return SftpConstants.SSH_FX_NO_SUCH_FILE;
- } else if (t instanceof InvalidHandleException) {
- return SftpConstants.SSH_FX_INVALID_HANDLE;
- } else if (t instanceof FileAlreadyExistsException) {
- return SftpConstants.SSH_FX_FILE_ALREADY_EXISTS;
- } else if (t instanceof DirectoryNotEmptyException) {
- return SftpConstants.SSH_FX_DIR_NOT_EMPTY;
- } else if (t instanceof NotDirectoryException) {
- return SftpConstants.SSH_FX_NOT_A_DIRECTORY;
- } else if (t instanceof AccessDeniedException) {
- return SftpConstants.SSH_FX_PERMISSION_DENIED;
- } else if (t instanceof EOFException) {
- return SftpConstants.SSH_FX_EOF;
- } else if (t instanceof OverlappingFileLockException) {
- return SftpConstants.SSH_FX_LOCK_CONFLICT;
- } else if ((t instanceof UnsupportedOperationException)
- || (t instanceof UnknownServiceException)) {
- return SftpConstants.SSH_FX_OP_UNSUPPORTED;
- } else if (t instanceof InvalidPathException) {
- return SftpConstants.SSH_FX_INVALID_FILENAME;
- } else if (t instanceof IllegalArgumentException) {
- return SftpConstants.SSH_FX_INVALID_PARAMETER;
- } else if (t instanceof UserPrincipalNotFoundException) {
- return SftpConstants.SSH_FX_UNKNOWN_PRINCIPAL;
- } else if (t instanceof FileSystemLoopException) {
- return SftpConstants.SSH_FX_LINK_LOOP;
- } else if (t instanceof SftpException) {
- return ((SftpException) t).getStatus();
- } else {
- return SftpConstants.SSH_FX_FAILURE;
- }
- }
-
- public static String resolveStatusMessage(int subStatus) {
- String message = DEFAULT_SUBSTATUS_MESSAGE.get(subStatus);
- return GenericUtils.isEmpty(message) ? ("Unknown error: " + subStatus) : message;
- }
-
- public static NavigableMap<String, Object> readAttrs(Buffer buffer, int version) {
- NavigableMap<String, Object> attrs = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- int flags = buffer.getInt();
- if (version >= SftpConstants.SFTP_V4) {
- int type = buffer.getUByte();
- switch (type) {
- case SftpConstants.SSH_FILEXFER_TYPE_REGULAR:
- attrs.put("isRegular", Boolean.TRUE);
- break;
- case SftpConstants.SSH_FILEXFER_TYPE_DIRECTORY:
- attrs.put("isDirectory", Boolean.TRUE);
- break;
- case SftpConstants.SSH_FILEXFER_TYPE_SYMLINK:
- attrs.put("isSymbolicLink", Boolean.TRUE);
- break;
- case SftpConstants.SSH_FILEXFER_TYPE_SOCKET:
- case SftpConstants.SSH_FILEXFER_TYPE_CHAR_DEVICE:
- case SftpConstants.SSH_FILEXFER_TYPE_BLOCK_DEVICE:
- case SftpConstants.SSH_FILEXFER_TYPE_FIFO:
- attrs.put("isOther", Boolean.TRUE);
- break;
- default: // ignored
- }
- }
-
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_SIZE) != 0) {
- attrs.put("size", buffer.getLong());
- }
-
- if (version == SftpConstants.SFTP_V3) {
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_UIDGID) != 0) {
- attrs.put("uid", buffer.getInt());
- attrs.put("gid", buffer.getInt());
- }
- } else {
- if ((version >= SftpConstants.SFTP_V6) && ((flags & SftpConstants.SSH_FILEXFER_ATTR_ALLOCATION_SIZE) != 0)) {
- @SuppressWarnings("unused")
- long allocSize = buffer.getLong(); // TODO handle allocation size
- }
-
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_OWNERGROUP) != 0) {
- attrs.put("owner", new DefaultGroupPrincipal(buffer.getString()));
- attrs.put("group", new DefaultGroupPrincipal(buffer.getString()));
- }
- }
-
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_PERMISSIONS) != 0) {
- attrs.put("permissions", permissionsToAttributes(buffer.getInt()));
- }
-
- if (version == SftpConstants.SFTP_V3) {
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_ACMODTIME) != 0) {
- attrs.put("lastAccessTime", readTime(buffer, version, flags));
- attrs.put("lastModifiedTime", readTime(buffer, version, flags));
- }
- } else if (version >= SftpConstants.SFTP_V4) {
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_ACCESSTIME) != 0) {
- attrs.put("lastAccessTime", readTime(buffer, version, flags));
- }
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_CREATETIME) != 0) {
- attrs.put("creationTime", readTime(buffer, version, flags));
- }
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_MODIFYTIME) != 0) {
- attrs.put("lastModifiedTime", readTime(buffer, version, flags));
- }
- if ((version >= SftpConstants.SFTP_V6) && (flags & SftpConstants.SSH_FILEXFER_ATTR_CTIME) != 0) {
- attrs.put("ctime", readTime(buffer, version, flags));
- }
-
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_ACL) != 0) {
- attrs.put("acl", readACLs(buffer, version));
- }
-
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_BITS) != 0) {
- @SuppressWarnings("unused")
- int bits = buffer.getInt();
- @SuppressWarnings("unused")
- int valid = 0xffffffff;
- if (version >= SftpConstants.SFTP_V6) {
- valid = buffer.getInt();
- }
- // TODO: handle attrib bits
- }
-
- if (version >= SftpConstants.SFTP_V6) {
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_TEXT_HINT) != 0) {
- @SuppressWarnings("unused")
- boolean text = buffer.getBoolean(); // TODO: handle text
- }
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_MIME_TYPE) != 0) {
- @SuppressWarnings("unused")
- String mimeType = buffer.getString(); // TODO: handle mime-type
- }
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_LINK_COUNT) != 0) {
- @SuppressWarnings("unused")
- int nlink = buffer.getInt(); // TODO: handle link-count
- }
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_UNTRANSLATED_NAME) != 0) {
- @SuppressWarnings("unused")
- String untranslated = buffer.getString(); // TODO: handle untranslated-name
- }
- }
- }
-
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_EXTENDED) != 0) {
- attrs.put("extended", readExtensions(buffer));
- }
-
- return attrs;
- }
-
- public static NavigableMap<String, byte[]> readExtensions(Buffer buffer) {
- int count = buffer.getInt();
- // NOTE
- NavigableMap<String, byte[]> extended = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- for (int i = 0; i < count; i++) {
- String key = buffer.getString();
- byte[] val = buffer.getBytes();
- byte[] prev = extended.put(key, val);
- ValidateUtils.checkTrue(prev == null, "Duplicate values for extended key=%s", key);
- }
-
- return extended;
- }
-
- public static <B extends Buffer> B writeExtensions(B buffer, Map<?, ?> extensions) {
- int numExtensions = GenericUtils.size(extensions);
- buffer.putInt(numExtensions);
- if (numExtensions <= 0) {
- return buffer;
- }
-
- extensions.forEach((key, value) -> {
- Objects.requireNonNull(key, "No extension type");
- Objects.requireNonNull(value, "No extension value");
- buffer.putString(key.toString());
- if (value instanceof byte[]) {
- buffer.putBytes((byte[]) value);
- } else {
- buffer.putString(value.toString());
- }
- });
-
- return buffer;
- }
-
- public static NavigableMap<String, String> toStringExtensions(Map<String, ?> extensions) {
- if (GenericUtils.isEmpty(extensions)) {
- return Collections.emptyNavigableMap();
- }
-
- // NOTE: even though extensions are probably case sensitive we do not allow duplicate name that differs only in case
- NavigableMap<String, String> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- extensions.forEach((key, value) -> {
- ValidateUtils.checkNotNull(value, "No value for extension=%s", key);
- String prev = map.put(key, (value instanceof byte[]) ? new String((byte[]) value, StandardCharsets.UTF_8) : value.toString());
- ValidateUtils.checkTrue(prev == null, "Multiple values for extension=%s", key);
- });
-
- return map;
- }
-
- public static NavigableMap<String, byte[]> toBinaryExtensions(Map<String, String> extensions) {
- if (GenericUtils.isEmpty(extensions)) {
- return Collections.emptyNavigableMap();
- }
-
- // NOTE: even though extensions are probably case sensitive we do not allow duplicate name that differs only in case
- NavigableMap<String, byte[]> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- extensions.forEach((key, value) -> {
- ValidateUtils.checkNotNull(value, "No value for extension=%s", key);
- byte[] prev = map.put(key, value.getBytes(StandardCharsets.UTF_8));
- ValidateUtils.checkTrue(prev == null, "Multiple values for extension=%s", key);
- });
-
- return map;
- }
-
- // for v4,5 see https://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#page-15
- // for v6 see https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#page-21
- public static List<AclEntry> readACLs(Buffer buffer, int version) {
- int aclSize = buffer.getInt();
- int startPos = buffer.rpos();
- Buffer aclBuffer = new ByteArrayBuffer(buffer.array(), startPos, aclSize, true);
- List<AclEntry> acl = decodeACLs(aclBuffer, version);
- buffer.rpos(startPos + aclSize);
- return acl;
- }
-
- public static List<AclEntry> decodeACLs(Buffer buffer, int version) {
- @SuppressWarnings("unused")
- int aclFlags = 0; // TODO handle ACL flags
- if (version >= SftpConstants.SFTP_V6) {
- aclFlags = buffer.getInt();
- }
-
- int count = buffer.getInt();
- // NOTE: although the value is defined as UINT32 we do not expected a count greater than Integer.MAX_VALUE
- ValidateUtils.checkTrue(count >= 0, "Invalid ACL entries count: %d", count);
- if (count == 0) {
- return Collections.emptyList();
- }
-
- List<AclEntry> acls = new ArrayList<>(count);
- for (int i = 0; i < count; i++) {
- int aclType = buffer.getInt();
- int aclFlag = buffer.getInt();
- int aclMask = buffer.getInt();
- String aclWho = buffer.getString();
- acls.add(buildAclEntry(aclType, aclFlag, aclMask, aclWho));
- }
-
- return acls;
- }
-
- public static AclEntry buildAclEntry(int aclType, int aclFlag, int aclMask, String aclWho) {
- UserPrincipal who = new DefaultGroupPrincipal(aclWho);
- return AclEntry.newBuilder()
- .setType(ValidateUtils.checkNotNull(decodeAclEntryType(aclType), "Unknown ACL type: %d", aclType))
- .setFlags(decodeAclFlags(aclFlag))
- .setPermissions(decodeAclMask(aclMask))
- .setPrincipal(who)
- .build();
- }
-
- /**
- * @param aclType The {@code ACE4_ACCESS_xxx_ACE_TYPE} value
- * @return The matching {@link AclEntryType} or {@code null} if unknown value
- */
- public static AclEntryType decodeAclEntryType(int aclType) {
- switch (aclType) {
- case SftpConstants.ACE4_ACCESS_ALLOWED_ACE_TYPE:
- return AclEntryType.ALLOW;
- case SftpConstants.ACE4_ACCESS_DENIED_ACE_TYPE:
- return AclEntryType.DENY;
- case SftpConstants.ACE4_SYSTEM_AUDIT_ACE_TYPE:
- return AclEntryType.AUDIT;
- case SftpConstants.ACE4_SYSTEM_ALARM_ACE_TYPE:
- return AclEntryType.ALARM;
- default:
- return null;
- }
- }
-
- public static Set<AclEntryFlag> decodeAclFlags(int aclFlag) {
- Set<AclEntryFlag> flags = EnumSet.noneOf(AclEntryFlag.class);
- if ((aclFlag & SftpConstants.ACE4_FILE_INHERIT_ACE) != 0) {
- flags.add(AclEntryFlag.FILE_INHERIT);
- }
- if ((aclFlag & SftpConstants.ACE4_DIRECTORY_INHERIT_ACE) != 0) {
- flags.add(AclEntryFlag.DIRECTORY_INHERIT);
- }
- if ((aclFlag & SftpConstants.ACE4_NO_PROPAGATE_INHERIT_ACE) != 0) {
- flags.add(AclEntryFlag.NO_PROPAGATE_INHERIT);
- }
- if ((aclFlag & SftpConstants.ACE4_INHERIT_ONLY_ACE) != 0) {
- flags.add(AclEntryFlag.INHERIT_ONLY);
- }
-
- return flags;
- }
-
- public static Set<AclEntryPermission> decodeAclMask(int aclMask) {
- Set<AclEntryPermission> mask = EnumSet.noneOf(AclEntryPermission.class);
- if ((aclMask & SftpConstants.ACE4_READ_DATA) != 0) {
- mask.add(AclEntryPermission.READ_DATA);
- }
- if ((aclMask & SftpConstants.ACE4_LIST_DIRECTORY) != 0) {
- mask.add(AclEntryPermission.LIST_DIRECTORY);
- }
- if ((aclMask & SftpConstants.ACE4_WRITE_DATA) != 0) {
- mask.add(AclEntryPermission.WRITE_DATA);
- }
- if ((aclMask & SftpConstants.ACE4_ADD_FILE) != 0) {
- mask.add(AclEntryPermission.ADD_FILE);
- }
- if ((aclMask & SftpConstants.ACE4_APPEND_DATA) != 0) {
- mask.add(AclEntryPermission.APPEND_DATA);
- }
- if ((aclMask & SftpConstants.ACE4_ADD_SUBDIRECTORY) != 0) {
- mask.add(AclEntryPermission.ADD_SUBDIRECTORY);
- }
- if ((aclMask & SftpConstants.ACE4_READ_NAMED_ATTRS) != 0) {
- mask.add(AclEntryPermission.READ_NAMED_ATTRS);
- }
- if ((aclMask & SftpConstants.ACE4_WRITE_NAMED_ATTRS) != 0) {
- mask.add(AclEntryPermission.WRITE_NAMED_ATTRS);
- }
- if ((aclMask & SftpConstants.ACE4_EXECUTE) != 0) {
- mask.add(AclEntryPermission.EXECUTE);
- }
- if ((aclMask & SftpConstants.ACE4_DELETE_CHILD) != 0) {
- mask.add(AclEntryPermission.DELETE_CHILD);
- }
- if ((aclMask & SftpConstants.ACE4_READ_ATTRIBUTES) != 0) {
- mask.add(AclEntryPermission.READ_ATTRIBUTES);
- }
- if ((aclMask & SftpConstants.ACE4_WRITE_ATTRIBUTES) != 0) {
- mask.add(AclEntryPermission.WRITE_ATTRIBUTES);
- }
- if ((aclMask & SftpConstants.ACE4_DELETE) != 0) {
- mask.add(AclEntryPermission.DELETE);
- }
- if ((aclMask & SftpConstants.ACE4_READ_ACL) != 0) {
- mask.add(AclEntryPermission.READ_ACL);
- }
- if ((aclMask & SftpConstants.ACE4_WRITE_ACL) != 0) {
- mask.add(AclEntryPermission.WRITE_ACL);
- }
- if ((aclMask & SftpConstants.ACE4_WRITE_OWNER) != 0) {
- mask.add(AclEntryPermission.WRITE_OWNER);
- }
- if ((aclMask & SftpConstants.ACE4_SYNCHRONIZE) != 0) {
- mask.add(AclEntryPermission.SYNCHRONIZE);
- }
-
- return mask;
- }
-
- public static <B extends Buffer> B writeACLs(B buffer, int version, Collection<? extends AclEntry> acl) {
- int lenPos = buffer.wpos();
- buffer.putInt(0); // length placeholder
- buffer = encodeACLs(buffer, version, acl);
- BufferUtils.updateLengthPlaceholder(buffer, lenPos);
- return buffer;
- }
-
- public static <B extends Buffer> B encodeACLs(B buffer, int version, Collection<? extends AclEntry> acl) {
- Objects.requireNonNull(acl, "No ACL");
- if (version >= SftpConstants.SFTP_V6) {
- buffer.putInt(0); // TODO handle ACL flags
- }
-
- int numEntries = GenericUtils.size(acl);
- buffer.putInt(numEntries);
- if (numEntries > 0) {
- for (AclEntry e : acl) {
- buffer = writeAclEntry(buffer, e);
- }
- }
-
- return buffer;
- }
-
- public static <B extends Buffer> B writeAclEntry(B buffer, AclEntry acl) {
- Objects.requireNonNull(acl, "No ACL");
-
- AclEntryType type = acl.type();
- int aclType = encodeAclEntryType(type);
- ValidateUtils.checkTrue(aclType >= 0, "Unknown ACL type: %s", type);
- buffer.putInt(aclType);
- buffer.putInt(encodeAclFlags(acl.flags()));
- buffer.putInt(encodeAclMask(acl.permissions()));
-
- Principal user = acl.principal();
- buffer.putString(user.getName());
- return buffer;
- }
-
- /**
- * Returns the equivalent SFTP value for the ACL type
- *
- * @param type The {@link AclEntryType}
- * @return The equivalent {@code ACE_SYSTEM_xxx_TYPE} or negative
- * if {@code null} or unknown type
- */
- public static int encodeAclEntryType(AclEntryType type) {
- if (type == null) {
- return Integer.MIN_VALUE;
- }
-
- switch(type) {
- case ALARM:
- return SftpConstants.ACE4_SYSTEM_ALARM_ACE_TYPE;
- case ALLOW:
- return SftpConstants.ACE4_ACCESS_ALLOWED_ACE_TYPE;
- case AUDIT:
- return SftpConstants.ACE4_SYSTEM_AUDIT_ACE_TYPE;
- case DENY:
- return SftpConstants.ACE4_ACCESS_DENIED_ACE_TYPE;
- default:
- return -1;
- }
- }
-
- public static long encodeAclFlags(Collection<AclEntryFlag> flags) {
- if (GenericUtils.isEmpty(flags)) {
- return 0L;
- }
-
- long aclFlag = 0L;
- if (flags.contains(AclEntryFlag.FILE_INHERIT)) {
- aclFlag |= SftpConstants.ACE4_FILE_INHERIT_ACE;
- }
- if (flags.contains(AclEntryFlag.DIRECTORY_INHERIT)) {
- aclFlag |= SftpConstants.ACE4_DIRECTORY_INHERIT_ACE;
- }
- if (flags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT)) {
- aclFlag |= SftpConstants.ACE4_NO_PROPAGATE_INHERIT_ACE;
- }
- if (flags.contains(AclEntryFlag.INHERIT_ONLY)) {
- aclFlag |= SftpConstants.ACE4_INHERIT_ONLY_ACE;
- }
-
- return aclFlag;
- }
-
- public static long encodeAclMask(Collection<AclEntryPermission> mask) {
- if (GenericUtils.isEmpty(mask)) {
- return 0L;
- }
-
- long aclMask = 0L;
- if (mask.contains(AclEntryPermission.READ_DATA)) {
- aclMask |= SftpConstants.ACE4_READ_DATA;
- }
- if (mask.contains(AclEntryPermission.LIST_DIRECTORY)) {
- aclMask |= SftpConstants.ACE4_LIST_DIRECTORY;
- }
- if (mask.contains(AclEntryPermission.WRITE_DATA)) {
- aclMask |= SftpConstants.ACE4_WRITE_DATA;
- }
- if (mask.contains(AclEntryPermission.ADD_FILE)) {
- aclMask |= SftpConstants.ACE4_ADD_FILE;
- }
- if (mask.contains(AclEntryPermission.APPEND_DATA)) {
- aclMask |= SftpConstants.ACE4_APPEND_DATA;
- }
- if (mask.contains(AclEntryPermission.ADD_SUBDIRECTORY)) {
- aclMask |= SftpConstants.ACE4_ADD_SUBDIRECTORY;
- }
- if (mask.contains(AclEntryPermission.READ_NAMED_ATTRS)) {
- aclMask |= SftpConstants.ACE4_READ_NAMED_ATTRS;
- }
- if (mask.contains(AclEntryPermission.WRITE_NAMED_ATTRS)) {
- aclMask |= SftpConstants.ACE4_WRITE_NAMED_ATTRS;
- }
- if (mask.contains(AclEntryPermission.EXECUTE)) {
- aclMask |= SftpConstants.ACE4_EXECUTE;
- }
- if (mask.contains(AclEntryPermission.DELETE_CHILD)) {
- aclMask |= SftpConstants.ACE4_DELETE_CHILD;
- }
- if (mask.contains(AclEntryPermission.READ_ATTRIBUTES)) {
- aclMask |= SftpConstants.ACE4_READ_ATTRIBUTES;
- }
- if (mask.contains(AclEntryPermission.WRITE_ATTRIBUTES)) {
- aclMask |= SftpConstants.ACE4_WRITE_ATTRIBUTES;
- }
- if (mask.contains(AclEntryPermission.DELETE)) {
- aclMask |= SftpConstants.ACE4_DELETE;
- }
- if (mask.contains(AclEntryPermission.READ_ACL)) {
- aclMask |= SftpConstants.ACE4_READ_ACL;
- }
- if (mask.contains(AclEntryPermission.WRITE_ACL)) {
- aclMask |= SftpConstants.ACE4_WRITE_ACL;
- }
- if (mask.contains(AclEntryPermission.WRITE_OWNER)) {
- aclMask |= SftpConstants.ACE4_WRITE_OWNER;
- }
- if (mask.contains(AclEntryPermission.SYNCHRONIZE)) {
- aclMask |= SftpConstants.ACE4_SYNCHRONIZE;
- }
-
- return aclMask;
- }
-
- /**
- * Encodes a {@link FileTime} value into a buffer
- *
- * @param <B> Type of {@link Buffer} being updated
- * @param buffer The target buffer instance
- * @param version The encoding version
- * @param flags The encoding flags
- * @param time The value to encode
- * @return The updated buffer
- */
- public static <B extends Buffer> B writeTime(B buffer, int version, int flags, FileTime time) {
- // for v3 see https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#page-8
- // for v6 see https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#page-16
- if (version >= SftpConstants.SFTP_V4) {
- buffer.putLong(time.to(TimeUnit.SECONDS));
- if ((flags & SftpConstants.SSH_FILEXFER_ATTR_SUBSECOND_TIMES) != 0) {
- long nanos = time.to(TimeUnit.NANOSECONDS);
- nanos = nanos % TimeUnit.SECONDS.toNanos(1);
- buffer.putInt((int) nanos);
- }
- } else {
- buffer.putInt(time.to(TimeUnit.SECONDS));
- }
-
- return buffer;
- }
-
- /**
- * Decodes a {@link FileTime} value from a buffer
- *
- * @param buffer The source {@link Buffer}
- * @param version The encoding version
- * @param flags The encoding flags
- * @return The decoded value
- */
- public static FileTime readTime(Buffer buffer, int version, int flags) {
- // for v3 see https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#page-8
- // for v6 see https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#page-16
- long secs = (version >= SftpConstants.SFTP_V4) ? buffer.getLong() : buffer.getUInt();
- long millis = TimeUnit.SECONDS.toMillis(secs);
- if ((version >= SftpConstants.SFTP_V4) && ((flags & SftpConstants.SSH_FILEXFER_ATTR_SUBSECOND_TIMES) != 0)) {
- long nanoseconds = buffer.getUInt();
- millis += TimeUnit.NANOSECONDS.toMillis(nanoseconds);
- }
- return FileTime.from(millis, TimeUnit.MILLISECONDS);
- }
-
- /**
- * Creates an "ls -l" compatible long name string
- *
- * @param shortName The short file name - can also be "." or ".."
- * @param attributes The file's attributes - e.g., size, owner, permissions, etc.
- * @return A {@link String} representing the "long" file name as per
- * <A HREF="https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02">SFTP version 3 - section 7</A>
- */
- public static String getLongName(String shortName, Map<String, ?> attributes) {
- String owner = Objects.toString(attributes.get("owner"), null);
- String username = OsUtils.getCanonicalUser(owner);
- if (GenericUtils.isEmpty(username)) {
- username = SftpUniversalOwnerAndGroup.Owner.getName();
- }
-
- String group = Objects.toString(attributes.get("group"), null);
- group = OsUtils.resolveCanonicalGroup(group, owner);
- if (GenericUtils.isEmpty(group)) {
- group = SftpUniversalOwnerAndGroup.Group.getName();
- }
-
- Number length = (Number) attributes.get("size");
- if (length == null) {
- length = 0L;
- }
-
- String lengthString = String.format("%1$8s", length);
- String linkCount = Objects.toString(attributes.get("nlink"), null);
- if (GenericUtils.isEmpty(linkCount)) {
- linkCount = "1";
- }
-
- Boolean isDirectory = (Boolean) attributes.get("isDirectory");
- Boolean isLink = (Boolean) attributes.get("isSymbolicLink");
- @SuppressWarnings("unchecked")
- Set<PosixFilePermission> perms = (Set<PosixFilePermission>) attributes.get("permissions");
- if (perms == null) {
- perms = EnumSet.noneOf(PosixFilePermission.class);
- }
- String permsString = PosixFilePermissions.toString(perms);
- String timeStamp = UnixDateFormat.getUnixDate((FileTime) attributes.get("lastModifiedTime"));
- StringBuilder sb = new StringBuilder(
- GenericUtils.length(linkCount) + GenericUtils.length(username) + GenericUtils.length(group)
- + GenericUtils.length(timeStamp) + GenericUtils.length(lengthString)
- + GenericUtils.length(permsString) + GenericUtils.length(shortName)
- + Integer.SIZE);
- sb.append(SftpHelper.getBool(isDirectory) ? 'd' : (SftpHelper.getBool(isLink) ? 'l' : '-')).append(permsString);
-
- sb.append(' ');
- for (int index = linkCount.length(); index < 3; index++) {
- sb.append(' ');
- }
- sb.append(linkCount);
-
- sb.append(' ').append(username);
- for (int index = username.length(); index < 8; index++) {
- sb.append(' ');
- }
-
- sb.append(' ').append(group);
- for (int index = group.length(); index < 8; index++) {
- sb.append(' ');
- }
-
- sb.append(' ').append(lengthString).append(' ').append(timeStamp).append(' ').append(shortName);
- return sb.toString();
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpUniversalOwnerAndGroup.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpUniversalOwnerAndGroup.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpUniversalOwnerAndGroup.java
deleted file mode 100644
index 68ab055..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpUniversalOwnerAndGroup.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.sshd.common.subsystem.sftp;
-
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.Set;
-
-import org.apache.sshd.common.NamedResource;
-
-/**
- * Some universal identifiers used in owner and/or group specification strings
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- * @see <A HREF="https://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#page-12">SFTP ACL</A>
- */
-public enum SftpUniversalOwnerAndGroup implements NamedResource {
- Owner, // The owner of the file.
- Group, // The group associated with the file.
- Everyone, // The world.
- Interactive, // Accessed from an interactive terminal.
- Network, // Accessed via the network.
- Dialup, // Accessed as a dialup user to the server.
- Batch, // Accessed from a batch job.
- Anonymous, // Accessed without any authentication.
- Authenticated, // Any authenticated user (opposite of ANONYMOUS).
- Service; // Access from a system service.
-
- public static final Set<SftpUniversalOwnerAndGroup> VALUES =
- Collections.unmodifiableSet(EnumSet.allOf(SftpUniversalOwnerAndGroup.class));
-
- private final String name;
-
- SftpUniversalOwnerAndGroup() {
- name = name().toUpperCase() + "@";
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public String toString() {
- return getName();
- }
-
- public static SftpUniversalOwnerAndGroup fromName(String name) {
- return NamedResource.findByName(name, String.CASE_INSENSITIVE_ORDER, VALUES);
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AbstractParser.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AbstractParser.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AbstractParser.java
deleted file mode 100644
index 15cb3fe..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AbstractParser.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.sshd.common.subsystem.sftp.extensions;
-
-import org.apache.sshd.common.util.ValidateUtils;
-
-/**
- * @param <T> Parse result type
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public abstract class AbstractParser<T> implements ExtensionParser<T> {
- private final String name;
-
- protected AbstractParser(String name) {
- this.name = ValidateUtils.checkNotNullAndNotEmpty(name, "No extension name");
- }
-
- @Override
- public final String getName() {
- return name;
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AclSupportedParser.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AclSupportedParser.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AclSupportedParser.java
deleted file mode 100644
index ea2d12d..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AclSupportedParser.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.sshd.common.subsystem.sftp.extensions;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.TreeSet;
-
-import org.apache.sshd.common.subsystem.sftp.SftpConstants;
-import org.apache.sshd.common.subsystem.sftp.extensions.AclSupportedParser.AclCapabilities;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
-import org.apache.sshd.common.util.logging.LoggingUtils;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class AclSupportedParser extends AbstractParser<AclCapabilities> {
- /**
- * The "acl-supported" information as per
- * <A HREF="https://tools.ietf.org/html/draft-ietf-secsh-filexfer-11">DRAFT 11 - section 5.4</A>
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
- public static class AclCapabilities implements Serializable, Cloneable {
- private static final long serialVersionUID = -3118426327336468237L;
- private int capabilities;
-
- public AclCapabilities() {
- this(0);
- }
-
- public AclCapabilities(int capabilities) {
- this.capabilities = capabilities;
- }
-
- public int getCapabilities() {
- return capabilities;
- }
-
- public void setCapabilities(int capabilities) {
- this.capabilities = capabilities;
- }
-
- @Override
- public int hashCode() {
- return getCapabilities();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
- if (obj == this) {
- return true;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
-
- return ((AclCapabilities) obj).getCapabilities() == getCapabilities();
- }
-
- @Override
- public AclCapabilities clone() {
- try {
- return getClass().cast(super.clone());
- } catch (CloneNotSupportedException e) {
- throw new RuntimeException("Failed to clone " + toString() + ": " + e.getMessage(), e);
- }
- }
-
- @Override
- public String toString() {
- return Objects.toString(decodeAclCapabilities(getCapabilities()));
- }
-
- private static class LazyAclCapabilityNameHolder {
- private static final String ACL_CAP_NAME_PREFIX = "SSH_ACL_CAP_";
- private static final Map<Integer, String> ACL_VALUES_MAP = LoggingUtils.generateMnemonicMap(SftpConstants.class, ACL_CAP_NAME_PREFIX);
- private static final Map<String, Integer> ACL_NAMES_MAP =
- Collections.unmodifiableMap(GenericUtils.flipMap(ACL_VALUES_MAP, GenericUtils.caseInsensitiveMap(), false));
- }
-
- @SuppressWarnings("synthetic-access")
- public static Map<String, Integer> getAclCapabilityNamesMap() {
- return LazyAclCapabilityNameHolder.ACL_NAMES_MAP;
- }
-
- /**
- * @param name The ACL capability name - may be without the "SSH_ACL_CAP_xxx" prefix.
- * Ignored if {@code null}/empty
- * @return The matching {@link Integer} value - or {@code null} if no match found
- */
- public static Integer getAclCapabilityValue(String name) {
- if (GenericUtils.isEmpty(name)) {
- return null;
- }
-
- name = name.toUpperCase();
- if (!name.startsWith(LazyAclCapabilityNameHolder.ACL_CAP_NAME_PREFIX)) {
- name += LazyAclCapabilityNameHolder.ACL_CAP_NAME_PREFIX;
- }
-
- Map<String, Integer> map = getAclCapabilityNamesMap();
- return map.get(name);
- }
-
- @SuppressWarnings("synthetic-access")
- public static Map<Integer, String> getAclCapabilityValuesMap() {
- return LazyAclCapabilityNameHolder.ACL_VALUES_MAP;
- }
-
- public static String getAclCapabilityName(int aclCapValue) {
- Map<Integer, String> map = getAclCapabilityValuesMap();
- String name = map.get(aclCapValue);
- if (GenericUtils.isEmpty(name)) {
- return Integer.toString(aclCapValue);
- } else {
- return name;
- }
- }
-
- public static Set<String> decodeAclCapabilities(int mask) {
- if (mask == 0) {
- return Collections.emptySet();
- }
-
- Set<String> caps = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
- Map<Integer, String> map = getAclCapabilityValuesMap();
- map.forEach((value, name) -> {
- if ((mask & value) != 0) {
- caps.add(name);
- }
- });
-
- return caps;
- }
-
- public static int constructAclCapabilities(Collection<Integer> maskValues) {
- if (GenericUtils.isEmpty(maskValues)) {
- return 0;
- }
-
- int mask = 0;
- for (Integer v : maskValues) {
- mask |= v;
- }
-
- return mask;
- }
-
- public static Set<Integer> deconstructAclCapabilities(int mask) {
- if (mask == 0) {
- return Collections.emptySet();
- }
-
- Map<Integer, String> map = getAclCapabilityValuesMap();
- Set<Integer> caps = new HashSet<>(map.size());
- for (Integer v : map.keySet()) {
- if ((mask & v) != 0) {
- caps.add(v);
- }
- }
-
- return caps;
- }
- }
-
- public static final AclSupportedParser INSTANCE = new AclSupportedParser();
-
- public AclSupportedParser() {
- super(SftpConstants.EXT_ACL_SUPPORTED);
- }
-
- @Override
- public AclCapabilities parse(byte[] input, int offset, int len) {
- return parse(new ByteArrayBuffer(input, offset, len));
- }
-
- public AclCapabilities parse(Buffer buffer) {
- return new AclCapabilities(buffer.getInt());
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ExtensionParser.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ExtensionParser.java
deleted file mode 100644
index cd74a26..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ExtensionParser.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.sshd.common.subsystem.sftp.extensions;
-
-import java.util.function.Function;
-
-import org.apache.sshd.common.NamedResource;
-import org.apache.sshd.common.util.NumberUtils;
-
-/**
- * @param <T> Result type
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public interface ExtensionParser<T> extends NamedResource, Function<byte[], T> {
- default T parse(byte[] input) {
- return parse(input, 0, NumberUtils.length(input));
- }
-
- T parse(byte[] input, int offset, int len);
-
- @Override
- default T apply(byte[] input) {
- return parse(input);
- }
-}