Is there any way to lock file, which i am reading with JSch sftp channel, to prevent other applications to modificate it while session is open?
The problem i have: while i am reading/writing file, some other application changes the file and its causes errors.
Currently i am reading file in such way:
ChannelSftp sftp = (ChannelSftp) session.openChannel("sftp");
InputStream stream = sftp.get("/some/file");
try {
BufferedReader br = new BufferedReader(new InputStreamReader(stream));
// read from br
} finally {
stream.close();
}
Rather than locking the file (which could adversely affect whatever application you suggest is changing the file), and presuming you have ssh access and permissions to do so you could copy the file into a temp file using an ssh command (if on a 'nix system: 'cp /some/file/ /some/temp/file/'), which in all likelihood will be much faster than transferring via scp. (See http://www.jcraft.com/jsch/examples/Exec.java.html for exec example). From there, scp-get the temp file. Lastly, if necessary, delete the temp file via an other JSch exec command.
Jsch at this time supports version 3 of the SFTP protocol. The wikipedia page contains links to different versions of the protocol. Version 3 is here, and the word "lock" doesn't appear anywhere in it. In other words, the protocol doesn't support locking, so there's nothing for Jsch to support.
SFTP versions 5 and 6 do contain support for locking remote files. However, Jsch doesn't support these protocol versions.
I'll add that OpenSSH, the most widely used SSH/SFTP server, only supports SFTP version 3. You'd have to use some other server software to have any hope of doing file locks.
Related
I have a Spring Boot program that runs in a server, and it needs to read file from a different machine (Both machines are Windows OS). In the remote machine, I do not use any web-server such as apache/nginx - and I don't want to. I want to directly read files from the disk.
What I want is to provide the required params (probably IP, user name and password of the remote host), and a path in the file system - to direct access to the files without web server.
public void readFile(String ip, String userName, String password, String path);
How can I achieve this?
You need to do a scp (which allows copying files from different machines) from Java. This library will help
Also a working example which copies a file from remote to local
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, 22);
...
String command = "scp -f "+rfile;
Channel channel = session.openChannel("exec");
((ChannelExec)channel).setCommand(command);
InputStream in = channel.getInputStream();
channel.connect();
// "in" contains the input stream of the file
You can do something like
activate FTP protocol on the other machine and use java ftp implementations
create a network shared drive and grant access to specific windows users within your domain. you just need to know the network drive url and can access the file as if it was locally
execute a seperate powershell /ssh / scp / ... task from within your java code to open a remote-session and transfer the file
write your own http-server application in java and run on it on the other pc and connect to it as a client
...
I am using JSch in a Java client to connect to a remote server and get some files using SFTP. The following code has been working fine for me: -
JSch ssh = new JSch();
JSch.setConfig(FileTransferConstants.STRICT_HOST_KEY_CHECKING, FileTransferConstants.NO);
Session session = ssh.getSession(userName, host, port);
session.setPassword(password);
session.connect();
Channel channel = session.openChannel(FileTransferConstants.SFTP);
channel.connect();
ChannelSftp sftp = (ChannelSftp) channel;
sftp.cd(remoteDirectoryPath);
sftp.lcd(localDirectoryPath);
sftp.get(remoteDirectoryPath + remoteFileName, remoteFileName);
The problem is that there has now been a change of site policy. I am no longer permitted to log on directly as this user (userName above). I must first log on as my personal user and then su into the user that has access to the files I want to SFTP.
I don't think there is anyway I can refactor the above code to achieve this and so I have started looking at using a shell or exec channel instead. I have had little success so far and cannot seem to find any examples on the web, so I would be very grateful for any advice or pointers in the right direction. Many thanks.
I do not think you can do this directly with JSch. But with some modification of its code, it's probably doable.
Note that my answer assumes that the server is *nix-based (what is backed by your reference to su) and uses OpenSSH SFTP server.
You have to open SSH "exec" channel, to execute something like:
sudo /bin/sftp-server
But on top of that channel, you need to build the ChannelSftp instance, not ChannelExec.
So you will need to implement Session.openChannel-like method, that will open exec channel, but create ChannelSftp for it.
For some background, see how it's possible to do sudo with WinSCP SFTP client.
Note that while the FAQ claims, that you won't be able to use password for the sudo, that's true for WinSCP. But as you have a full control of the session with JSch, you may be able to feed the password to sudo.
For that you might override the ChannelSftp.start() to write the password to the channel input, before starting the actual SFTP session.
You still need the requiretty option be off, as the SFTP cannot work with TTY.
For general considerations when automating operations using a different/root account, see:
Allowing automatic command execution as root on Linux using SSH
I want to read the content of a remote directory using java.
The directory is on a machine running Ubuntu. Right clicking on the folder should give the share folder option and its installed samba client for windows sharing, but I don't have any machine running Windows.
I'm looking for a java api library to access the remote directory content?
User will only provide username, password, ip and folder name.
eg [//172.17.0.1/sharefolder/demo/]
Thanks.
For a Samba Share:
Even SAMBA shares in linux use the same protocol as windows shares.
So the post here can help: How can I mount a windows drive in Java?
Basically, you could mount the shared location as a network drive using "net use" command .
You could call this either through windows console, or through a java Process.
For a SFTP location:
If you don't have a problem with calling/using an external command you could use sshfs (either out of java or through Process) to mount the remote directory into a local folder.
See: http://numberformat.wordpress.com/2010/03/01/how-to-mount-a-remote-ssh-filesystem-using-sshfs/
If you want pure java on how to access SFTP,I read that a library called JSch can be used to access SFTP directly from java. See:
http://chrisjordan.ca/post/15052396308/java-sftp
http://jcraft.com/jsch/examples/Sftp.java.html
If it's another type please specify
You might find the The Java CIFS Client Library having the API you need - it is useful for both server and client.
Here is an example taken from their documentation to retrieve a file:
import jcifs.smb.*;
jcifs.Config.setProperty( "jcifs.netbios.wins", "192.168.1.220" );
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("domain", "username", "password");
SmbFileInputStream in = new SmbFileInputStream("smb://host/c/My Documents/somefile.txt", auth);
byte[] b = new byte[8192];
int n;
while(( n = in.read( b )) > 0 ) {
System.out.write( b, 0, n );
}
For SFTP consider using JSCAPE's Secure FTP Factory. Documentation with code examples can be found here.
jsch-nio is a fully functional unix/linux java FileSystemProvider over ssh.
I've got a simple task for now: connect to a remote server and get list of files and their info (in particular date of creation).
Tried JSch, but it's like writing unix app 20 years ago. Would like to switch to sshj so if it's possible, please provide some code on how to achieve at least file listing and their info (ideally, I would like to get an array of File objects).
So how can I achieve the goal?
Thanks in advance.
NOTE: AFAIU it's only possible by having ls on server side and parsing it, isn't it?
They have examples bundled with their source distribution. Did you look a them? I found this in 2 minutes: sshj: how to execute remote command example
Edit:
Ok, you could execute for instance (basing on the example I linked):
final Command cmd = session.exec("ls -l /some/interesting/dir");
String lsOutput = cmd.getOutputAsString();
// parse lsOutput and extract required information
...
There is no simplier way if you want to do it over ssh, because it has no notion of files etc. It is just a remote shell. Maybe sftp could provide some better interface here, but I am no expert with sftp.
Here is the code for sftp (JSCH)
ChannelSftp sftp = (ChannelSftp)session.openChannel("sftp");
sftp.connect();
sftp.cd(DIRECTORY);
Vector v = null;
v = sftp.ls("*.txt"); //txt files only
Use with keyfile:
JSch jsch = new JSch();
jsch.setKnownHosts(myKonfig.getKnownHostsFile());
String privKeyFile = myKonfig.getPrivateKeyFile();
jsch.addIdentity(privKeyFile);
Oops, just saw that it doesn't return the creation time, just the modification time.
If you're just looking to get file information from the remote system, I would recommend using the SFTPClient class that's provided within sshj.
use the:
SFTPClient.ls(directory)
command to find all the remote files, then use the:
SFTPClient.stat(file)
to get all the information from the remote files including the date of modification.
I think I understand the difference between ASCII mode and Binary mode on regular FTP transfers -- in Binary mode the file is copied exactly, and in ASCII mode the client may modify line endings (stripping the Carriage Return from Windows -> UNIX or adding it in the other direction). However, I thought that the SFTP protocol only supported Binary mode style transfers; the source file would not be modified.
However, when using the JSch library to copy a file from Windows to UNIX, the Windows-style line endings are stripped. This is problematic because these files are retrieved by others, using various methods, for Windows machines, and I can't guarantee that their clients will re-add the Carriage Return before each Line Feed.
Properties properties = new Properties();
properties.setProperty("StrictHostKeyChecking", "no");
Session session = jsch.getSession(UserName, Address, Port);
session.setPassword(Password);
session.setConfig(properties);
session.connect();
ChannelSftp channel = (ChannelSftp)session.openChannel("sftp");
channel.connect();
channel.
channel.cd(SCPDir);
channel.put(new ByteArrayInputStream(WindowsStyleString.getBytes()), FileName);
channel.disconnect();
session.disconnect();
Is there something I can do to ensure that JSch transfers the files exactly? It is frustratingly lacking in documentation, so I'm not sure if there's some parameter of its or perhaps some additional SSH property I can specify to ensure verbatim transfer. And why is this even happening in the first place, when ASCII mode style modifications aren't part of the SFTP standard?
Another case of misdirection; I apologize for all of these unsatisfactory questions.
It turns out that on Windows, where I can debug, Java's ubiquitous toString returns line endings with the Carriage Return and Line Feed (\r\n). On the Linux production servers, toString returns only \n. However, every use I had of these toString objects, whether uploaded via FTP (even though the host is also a Linux machine), e-mailed, or used in SQL queries, either automatically appended \r or didn't require it. But SFTP didn't.
So I guess the lesson here is that toString probably returns a platform-appropriate line ending format, that org.apache.commons.net.ftp.FTPClient in ASCII mode will add \r before \n even if the FTP server is hosted on Linux (or perhaps that server is masquerading as Windows), and that e-mail and SQL don't particularly care which line endings they have.
SFTP supported only binary mode until version 4 and in version 4 and later (5, 6) binary mode is still default, though ASCII mode is available too. Whatever JSh does with your file is it's own initiative. Maybe it strips CRs itself, or maybe the server does this, I can't say for sure without seeing any kind of log that Jsh or server exposes.