/** * Create new channel every time a command needs to be executed. This is required to support execution of multiple * commands in parallel. All created channels are cleaned up when the session is closed. * * * @return a new {@link ChannelSftp} * @throws SftpException */ public ChannelSftp getSftpChannel() throws SftpException { try { ChannelSftp channelSftp = (ChannelSftp) this.session.openChannel("sftp"); channelSftp.connect(); return channelSftp; } catch (JSchException e) { throw new SftpException(0, "Cannot open a channel to SFTP server", e); } }
/** * Create a new sftp channel to execute commands. * * @param command to execute on the remote machine * @return a new execution channel * @throws SftpException if a channel could not be opened */ public ChannelExec getExecChannel(String command) throws SftpException { ChannelExec channelExec; try { channelExec = (ChannelExec) this.session.openChannel("exec"); channelExec.setCommand(command); channelExec.connect(); return channelExec; } catch (JSchException e) { throw new SftpException(0, "Cannot open a channel to SFTP server", e); } }
@Test public void testEnsureDirectoryExistsNotExisted() throws IOException, SftpException { final ProcessContext processContext = mock(ProcessContext.class); final ChannelSftp channel = mock(ChannelSftp.class); // stat for the parent was successful, simulating that dir2 exists, but no dir3. when(channel.stat("/dir1/dir2/dir3")).thenThrow(new SftpException(SSH_FX_NO_SUCH_FILE, "No such file")); final SFTPTransfer sftpTransfer = createSftpTransfer(processContext, channel); final MockFlowFile flowFile = new MockFlowFile(0); final File remoteDir = new File("/dir1/dir2/dir3"); sftpTransfer.ensureDirectoryExists(flowFile, remoteDir); // Dir existence check should be done by stat verify(channel).stat(eq("/dir1/dir2/dir3")); // dir3 was not found verify(channel).stat(eq("/dir1/dir2")); // so, dir2 was checked verify(channel).mkdir(eq("/dir1/dir2/dir3")); // dir2 existed, so dir3 was created. }
@Test public void testEnsureDirectoryExistsBlindlyAlreadyExisted() throws IOException, SftpException { final ProcessContext processContext = mock(ProcessContext.class); when(processContext.getProperty(SFTPTransfer.DISABLE_DIRECTORY_LISTING)).thenReturn(new MockPropertyValue("true")); final ChannelSftp channel = mock(ChannelSftp.class); // If the dir existed, a failure exception is thrown, but should be swallowed. doThrow(new SftpException(SSH_FX_FAILURE, "Failure")).when(channel).mkdir(eq("/dir1/dir2/dir3")); final SFTPTransfer sftpTransfer = createSftpTransfer(processContext, channel); final MockFlowFile flowFile = new MockFlowFile(0); final File remoteDir = new File("/dir1/dir2/dir3"); sftpTransfer.ensureDirectoryExists(flowFile, remoteDir); // stat should not be called. verify(channel, times(0)).stat(eq("/dir1/dir2/dir3")); verify(channel).mkdir(eq("/dir1/dir2/dir3")); // dir3 was created blindly. }
@Test public void testEnsureDirectoryExistsParentNotExisted() throws IOException, SftpException { final ProcessContext processContext = mock(ProcessContext.class); final ChannelSftp channel = mock(ChannelSftp.class); // stat for the dir1 was successful, simulating that dir1 exists, but no dir2 and dir3. when(channel.stat("/dir1/dir2/dir3")).thenThrow(new SftpException(SSH_FX_NO_SUCH_FILE, "No such file")); when(channel.stat("/dir1/dir2")).thenThrow(new SftpException(SSH_FX_NO_SUCH_FILE, "No such file")); final SFTPTransfer sftpTransfer = createSftpTransfer(processContext, channel); final MockFlowFile flowFile = new MockFlowFile(0); final File remoteDir = new File("/dir1/dir2/dir3"); sftpTransfer.ensureDirectoryExists(flowFile, remoteDir); // Dir existence check should be done by stat verify(channel).stat(eq("/dir1/dir2/dir3")); // dir3 was not found verify(channel).stat(eq("/dir1/dir2")); // dir2 was not found, too verify(channel).stat(eq("/dir1")); // dir1 was found verify(channel).mkdir(eq("/dir1/dir2")); // dir1 existed, so dir2 was created. verify(channel).mkdir(eq("/dir1/dir2/dir3")); // then dir3 was created. }
@Test public void testEnsureDirectoryExistsNotExistedFailedToCreate() throws IOException, SftpException { final ProcessContext processContext = mock(ProcessContext.class); final ChannelSftp channel = mock(ChannelSftp.class); // stat for the parent was successful, simulating that dir2 exists, but no dir3. when(channel.stat("/dir1/dir2/dir3")).thenThrow(new SftpException(SSH_FX_NO_SUCH_FILE, "No such file")); // Failed to create dir3. doThrow(new SftpException(SSH_FX_FAILURE, "Failed")).when(channel).mkdir(eq("/dir1/dir2/dir3")); final SFTPTransfer sftpTransfer = createSftpTransfer(processContext, channel); final MockFlowFile flowFile = new MockFlowFile(0); final File remoteDir = new File("/dir1/dir2/dir3"); try { sftpTransfer.ensureDirectoryExists(flowFile, remoteDir); fail("Should fail"); } catch (IOException e) { assertEquals("Failed to create remote directory /dir1/dir2/dir3 due to 4: Failed", e.getMessage()); } // Dir existence check should be done by stat verify(channel).stat(eq("/dir1/dir2/dir3")); // dir3 was not found verify(channel).stat(eq("/dir1/dir2")); // so, dir2 was checked verify(channel).mkdir(eq("/dir1/dir2/dir3")); // dir2 existed, so dir3 was created. }
@Test public void testEnsureDirectoryExistsBlindlyParentNotExisted() throws IOException, SftpException { final ProcessContext processContext = mock(ProcessContext.class); when(processContext.getProperty(SFTPTransfer.DISABLE_DIRECTORY_LISTING)).thenReturn(new MockPropertyValue("true")); final ChannelSftp channel = mock(ChannelSftp.class); final AtomicInteger mkdirCount = new AtomicInteger(0); doAnswer(invocation -> { final int cnt = mkdirCount.getAndIncrement(); if (cnt == 0) { // If the parent dir does not exist, no such file exception is thrown. throw new SftpException(SSH_FX_NO_SUCH_FILE, "Failure"); } else { logger.info("Created the dir successfully for the 2nd time"); } return true; }).when(channel).mkdir(eq("/dir1/dir2/dir3")); final SFTPTransfer sftpTransfer = createSftpTransfer(processContext, channel); final MockFlowFile flowFile = new MockFlowFile(0); final File remoteDir = new File("/dir1/dir2/dir3"); sftpTransfer.ensureDirectoryExists(flowFile, remoteDir); // stat should not be called. verify(channel, times(0)).stat(eq("/dir1/dir2/dir3")); // dir3 was created blindly, but failed for the 1st time, and succeeded for the 2nd time. verify(channel, times(2)).mkdir(eq("/dir1/dir2/dir3")); verify(channel).mkdir(eq("/dir1/dir2")); // dir2 was created successfully. }
@Test public void testEnsureDirectoryExistsBlindlyFailed() throws IOException, SftpException { final ProcessContext processContext = mock(ProcessContext.class); when(processContext.getProperty(SFTPTransfer.DISABLE_DIRECTORY_LISTING)).thenReturn(new MockPropertyValue("true")); final ChannelSftp channel = mock(ChannelSftp.class); doThrow(new SftpException(SSH_FX_PERMISSION_DENIED, "Permission denied")).when(channel).mkdir(eq("/dir1/dir2/dir3")); final SFTPTransfer sftpTransfer = createSftpTransfer(processContext, channel); final MockFlowFile flowFile = new MockFlowFile(0); final File remoteDir = new File("/dir1/dir2/dir3"); try { sftpTransfer.ensureDirectoryExists(flowFile, remoteDir); fail("Should fail"); } catch (IOException e) { assertEquals("Could not blindly create remote directory due to Permission denied", e.getMessage()); } // stat should not be called. verify(channel, times(0)).stat(eq("/dir1/dir2/dir3")); verify(channel).mkdir(eq("/dir1/dir2/dir3")); // dir3 was created blindly. }
@Test public void testEnsureDirectoryExistsFailedToStat() throws IOException, SftpException { final ProcessContext processContext = mock(ProcessContext.class); final ChannelSftp channel = mock(ChannelSftp.class); // stat for the parent was successful, simulating that dir2 exists, but no dir3. when(channel.stat("/dir1/dir2/dir3")).thenThrow(new SftpException(SSH_FX_FAILURE, "Failure")); final SFTPTransfer sftpTransfer = createSftpTransfer(processContext, channel); final MockFlowFile flowFile = new MockFlowFile(0); final File remoteDir = new File("/dir1/dir2/dir3"); try { sftpTransfer.ensureDirectoryExists(flowFile, remoteDir); fail("Should fail"); } catch (IOException e) { assertEquals("Failed to determine if remote directory exists at /dir1/dir2/dir3 due to 4: Failure", e.getMessage()); } // Dir existence check should be done by stat verify(channel).stat(eq("/dir1/dir2/dir3")); }
private void read(byte[] buf, int s, int l) throws IOException, SftpException { int i; while (l > 0) { i = io_in.read(buf, s, l); if (i <= 0) { throw new SftpException(SSH_FX_FAILURE, ""); } s += i; l -= i; } }
private void read(byte[] buf, int s, int l) throws IOException, SftpException{ int i=0; while(l>0){ i=io_in.read(buf, s, l); if(i<=0){ throw new SftpException(SSH_FX_FAILURE, ""); } s+=i; l-=i; } }
public int getServerVersion() throws SftpException{ if(!isConnected()){ throw new SftpException(SSH_FX_FAILURE, "The channel is not connected."); } return server_version; }
public void lcd(String path) throws SftpException{ path=localAbsolutePath(path); if((new File(path)).isDirectory()){ try{ path=(new File(path)).getCanonicalPath(); } catch(Exception e){} lcwd=path; return; } throw new SftpException(SSH_FX_NO_SUCH_FILE, "No such directory"); }
public void lcd(String path) throws SftpException{ path=localAbsolutePath(path); if((new File(path)).isDirectory()){ try{ path=(new File(path)).getCanonicalPath(); } catch(Exception e){} lcwd=path; return; } throw new SftpException(SSH_FX_NO_SUCH_FILE, "No such directory"); }
public int getServerVersion() throws SftpException{ if(!isConnected()){ throw new SftpException(SSH_FX_FAILURE, "The channel is not connected."); } return server_version; }
public String realpath(String path) throws SftpException{ try{ byte[] _path=_realpath(remoteAbsolutePath(path)); return Util.byte2str(_path, fEncoding); } catch(Exception e){ if(e instanceof SftpException) throw (SftpException)e; if(e instanceof Throwable) throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); throw new SftpException(SSH_FX_FAILURE, ""); } }
private void throwStatusError(Buffer buf, int i) throws SftpException { if (server_version >= 3 && buf.getLength() >= 4) { byte[] str = buf.getString(); throw new SftpException(i, Util.byte2str(str, UTF8)); } else { throw new SftpException(i, "Failure"); } }
public String realpath(String path) throws SftpException { try { byte[] _path = _realpath(remoteAbsolutePath(path)); return Util.byte2str(_path, fEncoding); } catch (Exception e) { if (e instanceof SftpException) throw (SftpException) e; throw new SftpException(SSH_FX_FAILURE, "", e); } }
@Test public void returnNullOnUnexistingFile() throws Exception { when(channel.stat(any())).thenThrow(new SftpException(SSH_FX_NO_SUCH_FILE, "No such file")); assertThat(client.getAttributes(path), is(nullValue())); }
@Test public void exceptionIsThrownOnError() throws Exception { expectedException.expect(MuleRuntimeException.class); expectedException.expectMessage(format("Could not obtain attributes for path %s", FILE_PATH)); when(channel.stat(any())).thenThrow(new SftpException(SSH_FX_PERMISSION_DENIED, EMPTY)); client.getAttributes(path); } }