An executable jar is distributed to users per network drive. I want to prevent users from running it directly on the network because it causes performance and other problems.
One solution can be to check the execution path and compare it with the network drive path, but what if the network drive path is not known in advance? Is there any other possibility?
I don't think you can do this in pure Java. I'm pretty sure you will need to either run an external command or make a call into native code to detect the whether the JAR file is on a network share.
The first part you need to do is to obtain the absolute path for the JAR file:
Class mainClass = MyMainClass.class;
File jarFile = new File(mainClass.getProtectionDomain()
.getCodeSource()
.getLocation()
.toURI());
I found a "gist" on github written by Aaron Digulla that does the second rest of the task:
https://gist.github.com/digulla/31eed31c7ead29ffc7a30aaf87131def
Aaron's code takes a Windows absolute path, extracts the drive letter and then runs the Windows net use <drive-letter>: command to test whether the drive is a share drive.
An alternative would be to implement the logic a batch file does the following:
Extract the drive name for the JAR file
Use net use ... to test for a share drive
Use the same technique to check that the Java installation is not on a share drive either1.
Use the java command to start the application
Finally, is probably a bad idea to refuse to run on a share drive. The user may have reasons to do this that you are not aware of. I would suggest prompting the user and giving the user the option of continuing anyway. Or something like that.
Alternatively, document in the application's installation instructions that it is inadvisable to install the JRE / JDK and the application on a share drive (or equivalent).
1 - A Java install on a share drive will give as bad if not worse performance than an application JAR on a share drive.
Related
I am writing a java application which iterates over all the files in a network share and searches the files for some keywords.
I am aware I can use the smbj library, but I want to use native windows/linux mounting.
I am using the net use command on windows and mount -t command on linux.
Is there any difference in mapping the drive to a drive letter?
(So that I can avoid the code to wait if no drive letter is available)
Obviously, I don't need the drive letter for the user, I am unmounting the drive at the end of my code.
Does mapping the drive make further calls to the drive faster?
(X:/Folder vs \Share\Folder)
I've used Commons IO to write a program that copy files and other things. But I want to copy a file to a local ip address \\10.x.x.x, but the user doesn't have rights to do the copy, so I need to put an ID and password to access it. However I cannot find a way I can do that.
To move file I use :
FileUtils.moveFileToDirectory(fichier, destDir,true);
But my directory is something like \\10.x.x.x\files and only a few users can write in that directory so I have an ID & password that let you move files there. I want that even if the users don't have rights to move files to that directory my program can do it.
It is not really the way Windows security works. If you really want to do it that way, you will have to use Java Native Interface or Java Native Access, and manage to call the WNetAddConnection function from Mpr.dll (and do not forget to call WNetCancelConnection when done).
But you would have to store a password in your program, which is poor security practice.
The standard way to do that would be to start a service that would run under a user that has access to the desired directory, and have your program to communicate with it using whatever you want, the simplest way being probably TCP/IP. But unless you have special requirement for that I would not recommend to use Jave for those kinds of program.
A more Java alternative would be to start a Tomcat service on server machine running under a user having access to the directory. That way you just have to develop a standard Java Web Application able to upload files that would save the files to the proper directory. But it would be a traditionnal and portable Java application with no need for JNI nor JNA.
If cannot use a Tomcat and do not want to invest to much on it, you could split the program in pieces :
one client program that copies files on a directory (on server machine) with File creation rights for everybody - can decays to the copy utility if nothing more has to be done or can easily written in Java
one server program that will run on server machine under a user that has full write permissions on target directory. This one can also be easily written in Java
you can easily install the server program as a service on the server machine with sc and srvany according to this answer on ServerFault
If you use a client program, you could easily add a digital signature file with each copied file, but as I said above, it is poor security practice and add little if any security. At least the program should be executable and not readable, and the sources should be kept hidden. It is better to log the users that copied the file and ask them what happened is you find a problem.
I write cross-platform java app and I need some place where I can store some amount of files. These files will be used by another java application that may run under another user. This mean that I cannot use:
System.getProperty("user.home");
since I may have no permissions to read/write these files. What I need is some way to get non-user-specific folder where every app can create/read/delete files (something like "C:\ProgramData" for windows).
Is there a cross-platform way to get such folder(at least for Windows and Linux), or if there is no any - what is the best way to get such folders for Windows(should work on XP-7), Linux and Android.
Any pieces of puzzle are welcomed.
I'm not aware of such such a cross-platform folder which is additionally readable by all users. But you can:
Define a specific folder for each OS, commons-lang may help you determining the platform (see SystemUtils)
Check if the folder read/writeable for the current user during application start-up.
Using a central configuration (where the data exchange folder is defined for this installation) may also be an option, but this depends on the packaging of your project.
I have a program, written in Java, which originally used its directory in Program Files to write files accessible to all users of this program. This required our users to run as administrator all the time. In an effort to alleviate that, we decided to move files which needed to be written during regular usage to the ProgramData folder using the %ALLUSERSPROFILE% environment variable. Using a subfolder in this directory for our application works great if it is designated as writable during the installation process, which works fine using NSIS.
The problem comes with upgrading existing users. The Java File API provides setWritable but this does not appear to work after testing on development machines. It looks as though the new file API with Java 7 would solve this problem, but with no release date on the horizon I would rather not wait.
It seems the simplest solution would be to use JNA to call the appropriate Windows API call to set this directory writable. Since upgrading the software necessitates admin rights, similar to installing, it should let this change go through fine. However, I'm unsure where to start, having never used JNA before or the Windows API. Suggestions as to which Windows library to load and what functions to call would be appreciated, especially if someone has encountered a similar problem before.
Well, I'm glad you gave some background...You could use JNA, but the easier way would be to execute a call to the command-line utility cacls. It's included by default in Windows XP installations, I believe, so it should do the trick for you. Try Runtime.getRuntime().exec("C:\\Windows\\System32\\cacls.exe"+options)
Check out the documentation here -> http://technet.microsoft.com/en-us/library/bb490872.aspx
I use the follow line:
Runtime.getRuntime().exec( "C:\\Windows\\System32\\icacls.exe \"%ProgramData%\my application" /grant *S-1-5-32-545:(OI)(CI)(W,M)" );
S-1-5-32-545 is the SID for BUILTIN\Users because the name work only on English systems. https://support.microsoft.com/de-de/kb/163846
This give the BUILTIN\Users write access to all files in the given directory independent which user has create it.
This Java code lists files in a directory on a Windows shared drive. Will it work correctly on a Unix system?
File directory = new File("\\\\server/Shared/stuff/mystuff");
for (File file: directory.listFiles()) {
System.out.println(file);
}
Short answer: No.
Long answer: Do you have samba installed? Even then you need to mount the the share. So it probably won't work.
EDIT
Java delegates the call to the underlying OS eventually. Since Unix doesn't know what the \\SERVERNAME path means, Java doesn't know what it means either. What you have to do, to get this to work is mount the drive explicitly using Samba. Your other option, if you are running Ubuntu, is look under .gvfs in your home directory. Ubuntu creates a mount there for your Samba shares, which you should be able to access using Java. If you don't want to rely on external tools, try JCIFS for a pure-Java solution.
No...
Just let the user select the right path and use an OS dependent file-selection dialog.
On my system (Debian Sid with Gnome 2.30 Desktop) I have to select "smb:///server/Shared/..." to achieve the same behaviour. I think, that GVFS (Gnome Virtual File System) using smbfs drivers handles the real connection in the background...
No, as that is a UNC Path, which is a windowsism.
Are you trying to access a windows share from unix? Then have a look at jcifs.
The counter question I get when seeing this is: "Why would you want to hard-code a path in your application?"
Even if it was just for the example and you intend to load the path from a property file or anything, I still think you are on the wrong track here.
First of all you will want to avoid absolute paths like the plague. Relative paths are sort of ok. You can use slash ('/') characters in paths hardcoded, it will work on both Windows and Linux/Mac. Basically all platforms.
Second of all, why use paths at all? This is the internet age. Use URL's! file: URL's will accomplish the same thing as file paths, but using URL's make your app accept resources from other sources such as web sites and FTP as well.
Third of all, avoid the File class. If you invent a good way to do that, you are out of the woodworks completely. Use URL's together with getResource and getResourceAsStream and your app will work platform independent and across network boundaries over the internet.