lib/src/main/java/edu/utexas/tacc/tapis/files/lib/clients/SSHDataClient.java
@Override
    public List<FileInfo> ls(@NotNull String remotePath, long limit, long offset) throws IOException, NotFoundException {
        remotePath = cleanAndRelativize(remotePath).toString();
        remotePath = StringUtils.isEmpty(remotePath) ? "/" : remotePath;
        long count = Math.min(limit, Constants.MAX_LISTING_SIZE);
        long startIdx = Math.max(offset, 0);

        List<FileInfo> filesList = new ArrayList<>();
        List<DirEntry> dirEntries = new ArrayList<>();
        Path absolutePath = Paths.get(rootDir, remotePath);
        Path rootDirPath = Paths.get(rootDir);
        SSHSftpClient sftpClient = connectionHolder.getSftpClient();
        try {
            Attributes attributes = sftpClient.stat(absolutePath.toString());
            if (attributes.isDirectory()) {
                Iterable<DirEntry> tmp = sftpClient.readDir(absolutePath.toString());
                tmp.forEach(dirEntries::add);
            } else {
                DirEntry entry = new DirEntry(remotePath, remotePath, attributes);
                dirEntries.add(entry);
            }
        } catch (IOException e) {
            if (e.getMessage().toLowerCase().contains("no such file")) {
                String msg = Utils.getMsg("FILES_CLIENT_SSH_NOT_FOUND", oboTenant, oboUser, systemId, username, host, remotePath);
                throw new NotFoundException(msg);
            } else {
                String msg = Utils.getMsg("FILES_CLIENT_SSH_OP_ERR1", oboTenant, oboUser, "ls", systemId, username, host, remotePath, e.getMessage());
                throw new IOException(msg, e);
            }
        } finally {
            sftpClient.close();
            connectionHolder.returnSftpClient(sftpClient);
        }

        // For each entry in the fileList received, get the fileInfo object
        for (DirEntry entry: dirEntries) {
            // Get the file attributes
            Attributes attrs = entry.getAttributes();
            FileInfo fileInfo = new FileInfo();
            // Ignore filename . and ..
            if (entry.getFilename().equals(".") || entry.getFilename().equals("..")) {
                continue;
            }
            Path entryPath = Paths.get(entry.getFilename());
            fileInfo.setName(entryPath.getFileName().toString());
            fileInfo.setLastModified(attrs.getModifyTime().toInstant());
            fileInfo.setSize(attrs.getSize());

            //Try to determine the Mimetype
            Path tmpPath = Paths.get(entry.getFilename());
            fileInfo.setMimeType(Files.probeContentType(tmpPath));
            if (attrs.isDirectory()) {
                fileInfo.setType("dir");
            } else {
                fileInfo.setType("file");
            }
            fileInfo.setOwner(String.valueOf(attrs.getUserId()));
            fileInfo.setGroup(String.valueOf(attrs.getGroupId()));
            fileInfo.setNativePermissions(FileStatInfo.getPermsFromInt(attrs.getPermissions()));
            //Path should be relative to rootDir
            Path tmpFilePath = Paths.get(rootDir, entry.getFilename());
            if (tmpFilePath.equals(absolutePath)) {
                String thePath = StringUtils.removeStart(entryPath.toString(), "/");
                fileInfo.setPath(thePath);
            } else {
                fileInfo.setPath(Paths.get(remotePath, entryPath.toString()).toString());
            }

            filesList.add(fileInfo);
        }
        filesList.sort(Comparator.comparing(FileInfo::getName));
        return filesList.stream().skip(startIdx).limit(count).collect(Collectors.toList());
    }
/**
     * Returns the files listing output on a remotePath
     *
     * @param remotePath Always relative to rootDir
     * @return list of FileInfo
     * @throws IOException       Generally a network error
     * @throws NotFoundException No file at target
     */
Returns the files listing output on a remotePath
@param remotePath Always relative to rootDir
@return list of FileInfo
@throws IOException       Generally a network error
@throws NotFoundException No file at target
Returns the files listing output on a remotePath @param remotePath Always relative to rootDir @return list of FileInfo @throws IOException Generally a network error @throws NotFoundException No file at target
@Override
    public List<FileInfo> ls(@NotNull String remotePath, long limit, long offset) throws IOException, NotFoundException {
        remotePath = cleanAndRelativize(remotePath).toString();
        remotePath = StringUtils.isEmpty(remotePath) ? "/" : remotePath;
        long count = Math.min(limit, Constants.MAX_LISTING_SIZE);
        long startIdx = Math.max(offset, 0);
        List<FileInfo> filesList = new ArrayList<>();
        List<DirEntry> dirEntries = new ArrayList<>();
        Path absolutePath = Paths.get(rootDir, remotePath);
        Path rootDirPath = Paths.get(rootDir);
        SSHSftpClient sftpClient = connectionHolder.getSftpClient();
        try {
            Attributes attributes = sftpClient.stat(absolutePath.toString());
            if (attributes.isDirectory()) {
                Iterable<DirEntry> tmp = sftpClient.readDir(absolutePath.toString());
                tmp.forEach(dirEntries::add);
            } else {
                DirEntry entry = new DirEntry(remotePath, remotePath, attributes);
                dirEntries.add(entry);
            }
        } catch (IOException e) {
            if (e.getMessage().toLowerCase().contains("no such file")) {
                String msg = Utils.getMsg("FILES_CLIENT_SSH_NOT_FOUND", oboTenant, oboUser, systemId, username, host, remotePath);
                throw new NotFoundException(msg);
            } else {
                String msg = Utils.getMsg("FILES_CLIENT_SSH_OP_ERR1", oboTenant, oboUser, "ls", systemId, username, host, remotePath, e.getMessage());
                throw new IOException(msg, e);
            }
        } finally {
            sftpClient.close();
            connectionHolder.returnSftpClient(sftpClient);
        }
        for (DirEntry entry: dirEntries) {
            Attributes attrs = entry.getAttributes();
            FileInfo fileInfo = new FileInfo();
            if (entry.getFilename().equals(".") || entry.getFilename().equals("..")) {
                continue;
            }
            Path entryPath = Paths.get(entry.getFilename());
            fileInfo.setName(entryPath.getFileName().toString());
            fileInfo.setLastModified(attrs.getModifyTime().toInstant());
            fileInfo.setSize(attrs.getSize());
            Path tmpPath = Paths.get(entry.getFilename());
            fileInfo.setMimeType(Files.probeContentType(tmpPath));
            if (attrs.isDirectory()) {
                fileInfo.setType("dir");
            } else {
                fileInfo.setType("file");
            }
            fileInfo.setOwner(String.valueOf(attrs.getUserId()));
            fileInfo.setGroup(String.valueOf(attrs.getGroupId()));
            fileInfo.setNativePermissions(FileStatInfo.getPermsFromInt(attrs.getPermissions()));
            Path tmpFilePath = Paths.get(rootDir, entry.getFilename());
            if (tmpFilePath.equals(absolutePath)) {
                String thePath = StringUtils.removeStart(entryPath.toString(), "/");
                fileInfo.setPath(thePath);
            } else {
                fileInfo.setPath(Paths.get(remotePath, entryPath.toString()).toString());
            }
            filesList.add(fileInfo);
        }
        filesList.sort(Comparator.comparing(FileInfo::getName));
        return filesList.stream().skip(startIdx).limit(count).collect(Collectors.toList());
    }
@ Override public List < FileInfo > ls ( @ NotNull String remotePath , long limit , long offset ) throws IOException , NotFoundException { remotePath = cleanAndRelativize ( remotePath ) . toString ( ) ; remotePath = StringUtils . isEmpty ( remotePath ) ? "/" : remotePath ; long count = Math . min ( limit , Constants . MAX_LISTING_SIZE ) ; long startIdx = Math . max ( offset , 0 ) ; List < FileInfo > filesList = new ArrayList < > ( ) ; List < DirEntry > dirEntries = new ArrayList < > ( ) ; Path absolutePath = Paths . get ( rootDir , remotePath ) ; Path rootDirPath = Paths . get ( rootDir ) ; SSHSftpClient sftpClient = connectionHolder . getSftpClient ( ) ; try { Attributes attributes = sftpClient . stat ( absolutePath . toString ( ) ) ; if ( attributes . isDirectory ( ) ) { Iterable < DirEntry > tmp = sftpClient . readDir ( absolutePath . toString ( ) ) ; tmp . forEach ( dirEntries :: add ) ; } else { DirEntry entry = new DirEntry ( remotePath , remotePath , attributes ) ; dirEntries . add ( entry ) ; } } catch ( IOException e ) { if ( e . getMessage ( ) . toLowerCase ( ) . contains ( "no such file" ) ) { String msg = Utils . getMsg ( "FILES_CLIENT_SSH_NOT_FOUND" , oboTenant , oboUser , systemId , username , host , remotePath ) ; throw new NotFoundException ( msg ) ; } else { String msg = Utils . getMsg ( "FILES_CLIENT_SSH_OP_ERR1" , oboTenant , oboUser , "ls" , systemId , username , host , remotePath , e . getMessage ( ) ) ; throw new IOException ( msg , e ) ; } } finally { sftpClient . close ( ) ; connectionHolder . returnSftpClient ( sftpClient ) ; } for ( DirEntry entry : dirEntries ) { Attributes attrs = entry . getAttributes ( ) ; FileInfo fileInfo = new FileInfo ( ) ; if ( entry . getFilename ( ) . equals ( "." ) || entry . getFilename ( ) . equals ( ".." ) ) { continue ; } Path entryPath = Paths . get ( entry . getFilename ( ) ) ; fileInfo . setName ( entryPath . getFileName ( ) . toString ( ) ) ; fileInfo . setLastModified ( attrs . getModifyTime ( ) . toInstant ( ) ) ; fileInfo . setSize ( attrs . getSize ( ) ) ; Path tmpPath = Paths . get ( entry . getFilename ( ) ) ; fileInfo . setMimeType ( Files . probeContentType ( tmpPath ) ) ; if ( attrs . isDirectory ( ) ) { fileInfo . setType ( "dir" ) ; } else { fileInfo . setType ( "file" ) ; } fileInfo . setOwner ( String . valueOf ( attrs . getUserId ( ) ) ) ; fileInfo . setGroup ( String . valueOf ( attrs . getGroupId ( ) ) ) ; fileInfo . setNativePermissions ( FileStatInfo . getPermsFromInt ( attrs . getPermissions ( ) ) ) ; Path tmpFilePath = Paths . get ( rootDir , entry . getFilename ( ) ) ; if ( tmpFilePath . equals ( absolutePath ) ) { String thePath = StringUtils . removeStart ( entryPath . toString ( ) , "/" ) ; fileInfo . setPath ( thePath ) ; } else { fileInfo . setPath ( Paths . get ( remotePath , entryPath . toString ( ) ) . toString ( ) ) ; } filesList . add ( fileInfo ) ; } filesList . sort ( Comparator . comparing ( FileInfo :: getName ) ) ; return filesList . stream ( ) . skip ( startIdx ) . limit ( count ) . collect ( Collectors . toList ( ) ) ; }
Returns the files listing output on a remotePath
 @param remotePath Always relative to rootDir
 @return list of FileInfo
 @throws IOException       Generally a network error
 @throws NotFoundException No file at target
Returns the files listing output on a remotePath @param remotePath Always relative to rootDir @return list of FileInfo @throws IOException Generally a network error @throws NotFoundException No file at target
// For each entry in the fileList received, get the fileInfo object // Get the file attributes // Ignore filename . and .. //Try to determine the Mimetype //Path should be relative to rootDir