If I have 2 Paths for files, both share the same FileStore, how can I verify with Java 17 whether they are pointing to the same file on disk (are hard-linked)? For Unix-like systems there seems at least to be a way to verify whether a file has other hardlinks (get Hard Link Count in Java), but on Windows/NTFS I haven't yet found a way to get either information, except of invoking fsutil hardlink list <file-path> and parsing the output. If necessary, a workaround using JNA would also fine for me.
PS: I have already searched Stackoverflow, but only found similar questions for Python or C#.
I doubt it can be done within Java alone.
Try to use getCanonicalPath() to at least get around relative and absolute path names. But this hardly gets you around symlinks, or symlinks in parent folders.
For such things in Linux systems there is the readlink command. There is lots to be found here on StackOverflow about it: https://stackoverflow.com/search?q=readlink
For Windows you already mentioned fsutil.
Files.isSameFile(path1, path2) checks whether they are hard-linked.
Related
In Java 7 it provides me a way to detect whether a file is symbolic link or not , but why anyone would want to know that .
Files.isSymbolicLink(target) //here target is a path.
I never needed that so far, just wondering what will be the use of it ?
Suppose you're writing a recursive directory copy - you may decide not to follow symbolic links. Or maybe you're creating an archive in a format that doesn't support symbolic links - you may want to warn the user if you encounter one. Or maybe you're writing a diff program, and you want to skip pairs of files which are actually the same file really.
Basically it's a reasonably common property of some files in a file system - why would Java not want to expose that information?
One really good reason you might care about symbolic links is because of security. Sometimes you might want to prevent letting people accessing files from outside a restricted area, so your app checks to make sure the file that is being accessed is not a symbolic link that leads outside of your application's sandbox.
For example, if you're building a network accessible application that runs as a user and that accesses files by path, like maybe a file sharing application, and you want to restrict where people can look for files on your users system, symbolic links could be a security problem.
I used
Files.createTempFile("Hello", "txt");
to create a temporary file and stored the returned Path.
I have an Eclipse IFile resource linked to the temporary file I created:
linkedFile.createLink(tempFile.toUri(), IResource.NONE, null);
If I want to get a Path back from this resource, I call
linkedFile.getLocation().toFile().toPath()
On my local machine, this works 100% fine. But on a remote test machine, I get two different paths:
from Files.createTempFile: C:\Users\USERNA~1\AppData\Local\Temp\Hello3606197456871226795txt
from getLocation().toFile().toPath() C:\Users\Username_Testing\AppData\Local\Temp\Hello3606197456871226795txt
The Folder Username_Testing and only that folder gets turned into a short filename, and only for my direct creation of it as a temporary.
These two paths are not considered equal by Path.equals(...), which is causing a failing of my tests on the remote machine.
In general, this makes me a bit nervous using Path.equals(...) even though in the actual real operation of the application I haven't had any issues yet. Is there a way I can force the system to always use long filenames? Is there something I'm missing that I should be aware of when I do path equality checks, or when converting paths from one form to another?
Update #1: This specific issue is caused by %TEMP% on the target windows machine returning a path using a short filename, that doesn't happen on my local machine. Only test code creates temporary files and folders so this won't affect the real application. The obvious solution to my current problem is fix %TEMP% so the tests run fine in both places, but this solution is not viable in the general sense. It would be nice if there was a way to rectify the situation without modifying the target computer or jumping into native or windows specific code, since I used no such code directly to get both paths.
I found a good, portable solution to my problem, no need to use any platform-specific code. The answer is actually quite simple:
Path.toRealPath()
used something like this:
Path correctedTempFile = tempFile.toRealPath()
Essentially, it is now using the toRealPath() version, which thankfully removes the short filenames, for comparisons against other Paths taken from Eclipse resources. I believe the Eclipse implementation is using only long paths for consistency, so I in turn will use toRealPath to get rid of any potential paths that may use short filenames
This question might help:
Is there a way to generate the 8.3 or 'short' (Windows) version of a file name in Java?
You can get the short path and compare the generated path against both so you know which one to use.
This question already has answers here:
How to check existence of a program in the path
(10 answers)
Closed 9 years ago.
I can print the path using System.getenv("PATH").
Then I probably can traverse those paths and use File to check if the file is exist.
Is there any faster way in Java ?
You can use Runtime.getRuntime().exec("command"); in try ... catch section. If app won't be in PATH you will get an exception.
[EDIT]
But .. this will execute app instead of check. Sorry.
Is there any faster way in Java ?
In terms of performance, no.
In terms of coding effort, probably no. Certainly I'm not aware of any 3rd-party Java library that will search the command search path to see if an executable exists.
Unfortunately searching for an executable on Windows is a little tricky because you have to account for the various types of executable ... based on file suffixes. Even on Linux / Unix you need to use the new Java 7 file attributes APIs to determine if a candidate file has the execute permissions set.
(I am aware that some commands can be run in ways that are harmless; e.g. they may support an option / argument that outputs a version string, or some help info. However, that only works in specific cases. I'm also aware that on Unix / Linux, there is a built-in shell command called "whereis" that can tell you if an executable command with a given name exists on the search path.)
Your approach will work.
I suggest using the File.listFiles(FileFilter filter) method on each directory in the path. This will make searching each directory simpler.
Short version
How do I configure the icedtea-plugin package for ubuntu precise in such a way that it executes all applets with a specific memory limit by default? Preferrably using command line tools and no graphical user interface.
Long version
I'm building a kiosk setup using java applets, and would like to increase the default memory limit for all these applets. The kiosk is based on ubuntu linux, using the icedtea-plugin package as a browser plugin. As building the kiosk is automated and headless, I'd rather configure it from the command line if possible.
Here is what I've found out so far:
I'll probably have to specify a -Xmx… command line argument which will be used when starting the java virtual machine for the plugin.
It is possible to pass such arguments using a parameter in the HTML code, i.e.
<param name="java_arguments" value="-Xmx…">.
But that would mean modifying all my HTML files, which I'd rather avoid. And there is a good chance that I'd have to sign my code to make this work, which adds quite a lot of problems in other places of my project.
On my desktop system, using the Oracle VM, there is an application ControlPanel which I can use to set these command line switches. It seems that the configuration gets written to a file ~/.java/deployment/deployment.properties, where it is associated with the key deployment.javaws.jre.0.args.
That key name is not described in the specs for that file. The number 0 seems to refer to one specific JVM, as represented in one row of the table in the control panel. For each JVM, there are several values besides this args value, all sharing a common index number.
According to this wiki section, IcedTea supports a similar file, located at ~/.icedtea/. Not sure whether that means ~/.icedtea/deployment.properties or rather ~/.icedtea/deployment/deployment.properties. IcedTea does not seem to come with a ControlPanel.
As you can see, there are many hints as to how this might work, but so far I haven't seen any definite answer as to what will work. There are still many open questions:
Do I have to create this icedtea deployment file?
Do I have to include a directory named deployment in the path?
Which is the minimal set of keys that I need to specify to make this file work as intended?
Is the args value even supported by OpenJDK, even if it is not described in the corresponding specification?
I guess I could try out all possible combinations to see whether one of them works, but doing so will take considerable time. So I'm asking here, to see if someone has experience in this, and can provide a quiecker answer. If not, I guess I'll answer my own question eventually, once I've tried things the hard way.
as oracle says: http://docs.oracle.com/javase/7/docs/webnotes/tsg/TSG-Desktop/html/plugin.html.
following environment variable should be set to add additional arguments to applets:
_JPI_VM_OPTIONS=-Xmx…
Moreover as the reffered site says:
Please note that you need to restart your browser after you set the environment variable. If you are setting this environment variable in the command shell, then you must use the same command shell to launch the browser so that the browser inherits the value of environment variable.
However if you doubt how to set environment variable in ubuntu, following post might be helpful: Make $JAVA_HOME easily changable in Ubuntu
I just had a look at the source code of the icedtea-web plugin. The part of the code which builds the command line seems to have no provision at all for including custom arguments, no matter their origin. So it does not matter which config files, HTML files or environment variables I edit, the code there will build the same command line to call java, disregarding all my whishes.
So if all configuration fails, what remains is hackery. One approach would be to patch the source code of the plugin, and make it include additional words into its command line. For a static addition, i.e. a single size change, this would be fairly easy. A more general fix would include the content of some environment variable, the way Peter's answer suggests. That would mean word-splitting the environment variable in question, and allocating the space for the array of words dynamically. Quite a bit of work at the C level.
As an alternative, one could tackle this at the level of the executed binary. The plugin apparently has the path of the executable hard-coded into it. In my case, this path is /usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java. One can rename that binary to java.orig, and put a shell script in its place, with the following content:
#!/bin/bash
for i in "$#"; do
if [[ "${i}" == sun.applet.PluginMain ]]; then
exec "$0.orig" -Xmx512m "$#"
fi
done
exec "$0.orig" "$#"
One consequence of this approach is the fact that ps will no longer print these applets as java but instead as java.orig. Should not be a problem in most cases.
Supposing I have a File f that represents a directory, then f.delete() will only delete the directory if it is empty. I've found a couple of examples online that use File.listFiles() or File.list() to get all the files in the directory and then recursively traverses the directory structure and delete all the files. However, since it's possible to create infinitely recursive directory structures (in both Windows and Linux (with symbolic links)) presumably it's possible that programs written in this style might never terminate.
So, is there a better way to write such a program so that it doesn't fall into these pitfalls? Do I need to keep track of everywhere I've traversed and make sure I don't go around in circles or is there a nicer way?
Update: In response to some of the answers (thanks guys!) - I'd rather the code didn't follow symbolic links and stayed within the directory it was supposed to delete. Can I rely on the Commons-IO implementation to do that, even in the Windows case?
If you really want your recursive directory deletion to follow through symbolic links, then I don't think there is any platform independent way of doing so without keeping track of all the directories you have traversed.
However, in pretty much every case I can think of you would just want to delete the actual symbolic link pointing to the directory rather than recursively following through the symbolic link.
If this is the behaviour you want then you can use the FileUtils.deleteDirectory method in Apache Commons IO.
Try Apache Commons IO for a tested implementation.
However, I don't think it this handles the infinite-recursion problem.
File.getCanonicalPath() will tell you the “real” name of the file, including resolved symlinks. When while scanning you come across a directory you alread know (because you stored them in a Map) bail out.
If you could know which files are symlinks, you could just skip over those.
There is unfortunately no "clean" way of detecting symlinks in Java. Check out this pure Java workaround or this one involving native code.
At least under MacOSX, deleting a symbolic link to a directory does not delete the directory itself, and can therefore be deleted even if the target directory is not empty.
I assume this holds for most POSIX operating systems. And as far as I know, links under windows are also just files, and can be deleted as such from a Java program.