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, 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:   
            }
        }
        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();   
            }
            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();
                }
               
            }
            if (version >= SftpConstants.SFTP_V6) {
                if ((flags & SftpConstants.SSH_FILEXFER_ATTR_TEXT_HINT) != 0) {
                    @SuppressWarnings("unused")
                    boolean text = buffer.getBoolean();
                }
                if ((flags & SftpConstants.SSH_FILEXFER_ATTR_MIME_TYPE) != 0) {
                    @SuppressWarnings("unused")
                    String mimeType = buffer.getString();
                }
                if ((flags & SftpConstants.SSH_FILEXFER_ATTR_LINK_COUNT) != 0) {
                    @SuppressWarnings("unused")
                    int nlink = buffer.getInt();
                }
                if ((flags & SftpConstants.SSH_FILEXFER_ATTR_UNTRANSLATED_NAME) != 0) {
                    @SuppressWarnings("unused")
                    String untranslated = buffer.getString();
                }
            }
        }
        if ((flags & SftpConstants.SSH_FILEXFER_ATTR_EXTENDED) != 0) {
            attrs.put("extended", readExtensions(buffer));
        }
        return attrs;
    }
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: } } 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(); } 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(); } } if (version >= sftpconstants.sftp_v6) { if ((flags & sftpconstants.ssh_filexfer_attr_text_hint) != 0) { @suppresswarnings("unused") boolean text = buffer.getboolean(); } if ((flags & sftpconstants.ssh_filexfer_attr_mime_type) != 0) { @suppresswarnings("unused") string mimetype = buffer.getstring(); } if ((flags & sftpconstants.ssh_filexfer_attr_link_count) != 0) { @suppresswarnings("unused") int nlink = buffer.getint(); } if ((flags & sftpconstants.ssh_filexfer_attr_untranslated_name) != 0) { @suppresswarnings("unused") string untranslated = buffer.getstring(); } } } if ((flags & sftpconstants.ssh_filexfer_attr_extended) != 0) { attrs.put("extended", readextensions(buffer)); } return attrs; }