Невозможно переименовать файл, используя Apache Commons VFS для Vsftpd в Ubuntu 18.04 - PullRequest
4 голосов
/ 05 октября 2019

Я пытаюсь переименовать файл на сервере vsftpd, используя apache commons vfs, функция moveTo работает нормально в локальной операционной системе (Kubuntu 19.04) и на сервере VSFTPD, но когда я пытаюсь переименовать файл в тестовой среде, в которой есть ubuntu 18.04Я не могу переименовать файл, получаю исключение.

С этим кодом:

    public static boolean move(String hostName, String username, String password, String remoteSrcFilePath,
        String remoteDestFilePath, byte [] data) {

    FileObject remoteFile = null;
    FileObject remoteDestFile = null;
    boolean result = false;

    try (StandardFileSystemManager manager = new StandardFileSystemManager()){
        manager.init();

        // Create remote object
        remoteFile = manager.resolveFile(
                createConnectionString(hostName, username, password, remoteSrcFilePath), createDefaultOptions());
        remoteDestFile = manager.resolveFile(
                createConnectionString(hostName, username, password, remoteDestFilePath), createDefaultOptions());

        if (!remoteDestFile.exists() && remoteFile.exists()) {
            remoteFile.moveTo(remoteDestFile);
            if(null != data)
                writeData(remoteDestFile, data);
            result =  true;
        }else {
            throw new DataIntegrityViolationException("Destination path already exists");
        }
    } catch (IOException e) {
        logger.error("Error while renaming/moving file",e);
    }  finally {
        try {
            if(null != remoteDestFile)
                remoteDestFile.close();

            if(null != remoteFile)
                remoteFile.close();

        } catch (FileSystemException e) {
            logger.warn("error while closing fileobject "+e.getMessage());
        }
    }
    return result;
}

    public static FileSystemOptions createDefaultOptions() throws FileSystemException {
    // Create SFTP options
    FileSystemOptions opts = new FileSystemOptions();

    // SSH Key checking
    SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(opts, "no");

    /*
     * Using the following line will cause VFS to choose File System's Root as VFS's
     * root. If I wanted to use User's home as VFS's root then set 2nd method
     * parameter to "true"
     */
    // Root directory set to user home
    SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);

    // Timeout is count by Milliseconds
    SftpFileSystemConfigBuilder.getInstance().setConnectTimeoutMillis(opts, 10000);

    return opts;
    }
}

У меня есть это исключение

org.apache.commons.vfs2.FileSystemException: Could not determine if file "sftp://ftpuser:***@ip_address/home/ftpuser/ftp/1/Documents/test1/test2" is writeable

Обратите внимание на приведенный выше кодочень хорошо работает на местном уровне.

Ответы [ 2 ]

3 голосов
/ 11 октября 2019

Если вы будете следовать исходному коду для apache commons vfs для moveTo () , вы найдете:

if (canRenameTo(destFile)) {            //src and dest have the same FS
  if (!getParent().isWriteable()) {     // <-- it could throw the same exception here
    throw new FileSystemException("vfs.provider/rename-parent-read-only.error", getName(),
                    getParent().getName());
  }
} else {
  if (!isWriteable()) {    // <---- it throws inside here (IMO) rather than returning false 
    throw new FileSystemException("vfs.provider/rename-read-only.error", getName());
  }
}

..., вы обнаружите, чтоmoveTo() сгенерирует исключение, которое вы видите, если целевой файл не доступен для записи, но катастрофическим образом, как в isWriteable(file), создает исключение внутри своего тела, а не возвращает false.

Мой первыйвызов должен был бы проверить, что и sftpd , и ftp пользователь могут писать в каталог, куда вы хотите переместить ваш файл.

HTH!

0 голосов
/ 26 октября 2019

@ diginoise Я пробовал все время, используя Apache Commons VFS, но это не сработало, и только для переименования я переключаю на Jsch ниже, это рабочий код для локального и удаленного сервера

private static ChannelSftp setupJsch(String hostName, String username, String password) throws JSchException  {
    JSch jsch = new JSch();
    JSch.setConfig("StrictHostKeyChecking", "no");
    jsch.setKnownHosts("/home/"+username+"/.ssh/known_hosts");
    Session jschSession = jsch.getSession(username, hostName);
    jschSession.setPassword(password);
    jschSession.connect();
    return (ChannelSftp) jschSession.openChannel("sftp");
}

public static boolean renameFile(String hostName, String username, String password, String remoteSrcFilePath,
        String remoteDestFilePath) {

    boolean result = false;

    ChannelSftp channelSftp = null;
    try {

        channelSftp = setupJsch(hostName,username,password);
        channelSftp.connect();
        channelSftp.rename(remoteSrcFilePath, remoteDestFilePath);
        result = true;
    }catch(JSchException | SftpException  e) {
        logger.error("Error while renaming file sftp ",e);
    }finally {
        sftpCleanUp(channelSftp);
    }

    return result;  
}

private static void sftpCleanUp(ChannelSftp channelSftp) {
    if(null != channelSftp) {
        channelSftp.disconnect();
        channelSftp.exit();
    }
}
...