Covert Symbolic Link folder to Hard Link Folder - java

I created a symbolic Link folder which contains list of files. Is there any way to convert the Symbolic Link to HardLink using java?

To create a hard link using java, you can use :
Path newLink = ...;
Path existingFile = ...;
try {
Files.createLink(newLink, existingFile);
} catch (IOException x) {
System.err.println(x);
} catch (UnsupportedOperationException x) {
// Some file systems do not
// support adding an existing
// file to a directory.
System.err.println(x);
}
So, in your case newLink should be the oldSymbolicLink that you've created, and the existingFile represent its target.
To get the target of a symbolic link you may use
Files.readSymbolicLink(oldSymbolicLink));
Oracle Doc: Links, Symbolic or Otherwise

The Java doc as pointed out by others says that hard links on directories cannot be created. So, instead of telling you how to create hard link to directories, I am going to explain why you cannot create hard link on directories.
Hardlinks are on directories can cause loops when you are trying to traverse the directory tree.
For example if you have a directory /foo/bar and a symbolic link /foo/bar/baz pointing to ../bar, when you try to traverse this tree, you will run into an infinite loop.
/foo/
/foo/bar
/foo/bar/baz
/foo/bar/baz/bar
/foo/bar/baz/bar/baz
...
Now, if baz is a symlink to ../bar, it is simple to fix by unlinking baz using the unlink(2) system call (because unlink does not follow symlinks). However, if baz was a hard link, it would have been much harder (no pun intended) to fix this. In the book "Advanced Programming in Unix Environment", Stephen Rago notes that Rich Stevens corrupted his file system while trying this experiment (and fsck was unable to recover it)

Related

How to read a symlink file in Java?

I want to read the contents of a symlink in Java without following the symlink. I know that there are many functions in Files that allow for the LinkOption.NOFOLLOW_LINKS option, including Files.copy(symlinkpath, newsymlinkpath, LinkOption.NOFOLLOW_LINKS), however, it looks like input streams like FileInputStream don't have this same option (it will try to follow symlinks by default).
It seems like it should be easy to read the byte representation of a symlink into a buffer in Java, but I can't seem to figure it out.
java.nio.file.Files has readSymbolicLink which does what you want.
Reads the target of a symbolic link (optional operation).
If the file system supports symbolic links then this method is used to read the target of the link, failing if the file is not a symbolic link. The target of the link need not exist. The returned Path object will be associated with the same file system as link.
Example:
try {
Path file = Files.readSymbolicLink(link);
} catch (IOException x) {
System.err.println(x);
}

Java can't access file on local path

Asked this question, having already tried possible solutions in other questions here on stack but that didn't allow me to fix the problem.
As in the title, I have created a java utility with which I have to perform operations on text files, in particular I have to perform simple operations to move between directories, copy from one directory to another, etc.
To do this I have used the java libraries java.io.File and java.nio.*, And I have implemented two functions for now,copyFile(sourcePath, targetPath) and moveFile(sourcePath, targetPath).
To develop this I am using a mac, and the files are under the source path /Users/myname/Documents/myfolder/F24/archive/, and my target path is /Users/myname/Documents/myfolder/F24/target/.
But when I run my code I get a java.nio.file.NoSuchFileException: /Users/myname/Documents/myfolder/F24/archive
Having tried the other solutions here on stack and java documentation already I haven't been able to fix this yet ... I accept any advice or suggestion
Thank you all
my code:
// copyFile: funzione chiamata per copiare file
public static boolean copyFile(String sourcePath, String targetPath){
boolean fileCopied = true;
try{
Files.copy(Paths.get(sourcePath), Paths.get(targetPath), StandardCopyOption.REPLACE_EXISTING);
}catch(Exception e){
String sp = Paths.get(sourcePath)+"/";
fileCopied = false;
System.out.println("Non posso copiare i file dalla cartella "+sp+" nella cartella "+Paths.get(targetPath)+" ! \n");
e.printStackTrace();
}
return fileCopied;
}
Files.copy cannot copy entire directories. The first 'path' you pass to Files.copy must ALL:
Exist.
Be readable by the process that runs the JVM. This is non-trivial on a mac, which denies pretty much all disk rights to all apps by default until you give it access. This can be tricky for java apps. I'm not quite sure how you fix it (I did something on my mac to get rid of that, but I can't remember what - possibly out of the box java apps just get to read whatever they want and it's only actual mac apps that get pseudo-sandboxed. Point is, there's a chance it's mac's app access control denying it even if the unix file rights on this thing indicate you ought to be able to read it).
Be a plain old file and not a directory or whatnot.
Files.move can (usually - depends on impl and underlying OS) usually be done to directories, but not Files.copy. You're in a programming language, not a shell. If you want to copy entire directories, write code that does this.
Not sure whether my comment is understood though answered.
Ìn java SE target must not be the target directory. In other APIs of file copying
one can say COPY FILE TO DIRECTORY. In java not so; this was intentionally designed to remove one error cause.
That style would be:
Path source = Paths.get(sourcePath);
if (Files.isRegularFile(source)) {
Path target = Paths.get(targetPath);
Files.createDirectories(target);
if (Files.isDirectory(target)) {
target = Paths.get(targetPath, source.getFileName().toString());
// Or: target = target.resolve(source.getFileName().toString());
}
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
}
Better ensure when calling to use the full path.

How do I check if a File is a symbolic link? [duplicate]

In a DirectoryWalker class I want to find out if a File instance is actually a symbolic link to a directory (assuming, the walker walks on UNIX systems). Given, I already know the instance is a directory, would the following be a reliable condition to determine the symbolic link?
File file;
// ...
if (file.getAbsolutePath().equals(file.getCanonicalPath())) {
// real directory ---> do normal stuff
}
else {
// possible symbolic link ---> do link stuff
}
The technique used in Apache Commons uses the canonical path to the parent directory, not the file itself. I don't think that you can guarantee that a mismatch is due to a symbolic link, but it's a good indication that the file needs special treatment.
This is Apache code (subject to their license), modified for compactness.
public static boolean isSymlink(File file) throws IOException {
if (file == null)
throw new NullPointerException("File must not be null");
File canon;
if (file.getParent() == null) {
canon = file;
} else {
File canonDir = file.getParentFile().getCanonicalFile();
canon = new File(canonDir, file.getName());
}
return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
}
Java 1.6 does not provide such low level access to the file system. Looks like NIO 2, which should be included in Java 1.7, will have support for symbolic links. A draft of the new API is available. Symbolic links are mentioned there, creating and following them is possible. I'm not exactly sure that which method should be used to find out whether a file is a symbolic link. There's a mailing list for discussing NIO 2 - maybe they will know.
Also, watch out for file.isFile() and file.isDirectory() both returning results based on the resolved file and therefore both returning false when file refers to a symlink where the target doesn't exist.
(I know this isn't a useful answer in itself but it tripped me up a couple of times so thought I should share)
It looks like getCanonicalPath() can do other things that might make it different from the absolute path.
This method first converts this pathname to absolute form if necessary, as if by invoking the getAbsolutePath() method, and then maps it to its unique form in a system-dependent way. This typically involves removing redundant names such as "." and ".." from the pathname, resolving symbolic links (on UNIX platforms), and converting drive letters to a standard case (on Microsoft Windows platforms).
But it might work for the vast majority of your use cases; your mileage may vary.
If you are already coding something specifically for *nix, then you could do a shell command from Java like this:
Process p = Runtime.getRuntime().exec(new String[]{"test", "-h", yourFileName});
p.waitFor();
if (p.exitValue() == 0)
System.out.println("This file is a symbolic link");
else
System.out.println("This file is not a symbolic link");
That's very specific to *nix, but it does at least work.
Sorry to reply to such an old post, but I was looking for a solution for Windows systems some time back, and some of the previous answers didn't work out for me. If you're not concerned with cross platform compatibility and only need a solution for Windows, the following technique worked well for my purposes.
File f = new File("whatever file or folder");
if (f instanceof ShellFolder) {
ShellFolder sf = (ShellFolder)f;
if (sf.isLink()) {
// Your code when it's a link
}
}
I thought I would share some good fortune I had in dealing with this issue. I am using JDK 1.6.0_23 and so I cannot benefit from NIO2. I am building and running on Windows 7 /x64 ONLY so mileage may vary in other environments. Unfortunately, other solutions here did not work for me in avoiding NullPointerExceptions caused when attempting to traverse a junction (probably because junction != symlink....). While I am not constrained by JDK version, I decided to keep at the problem for a bit longer.
I had this code which would cause a NullPointerException if used on a symbolic link or when encountering the 'System Volume Information' directory. (Note, traverseItem.f() returns an object of type java.io.File)
if (traverseItem.f().isDirectory) {
for (File item : traverseItem.f().listFiles()) {
So, it is supposedly a directory but calling listFiles() on it causes an NPE. What to do? I spied the list() method and wondered if it would exhibit the same behavior. What I discovered was the following:
Calling list() on a File describing an empty folder returns a String[] array of length zero. However, calling list() on a File describing a junction which would otherwise crash from listFiles() returns null
I was able to avoid the NullPointerExceptions by adding the following test before calling listFiles()
String[] contents = traverseItem.f().list();
if (contents != null) { //Non-traversible if null, possibly junction or ???
It remains to exhaustively test all cases of junction, symbolic link, hard link, and dare I mention it, shortcut, but this may help some.

How does Java resolve a relative path in new File()?

I am trying to understand the way Java resolves relative path in while creating a File object.
OS used: Windows
For the below snippet, I am getting an IOException as it cannot find the path:
#Test
public void testPathConversion() {
File f = new File("test/test.txt");
try {
f.createNewFile();
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
} catch (Exception e) {
e.printStackTrace();
}
}
My understanding here is, Java treats the path provided as absolute and returns an error when the path does not exist. So it makes sense.
When I update the above code to use relative path:
#Test
public void testPathConversion() {
File f = new File("test/../test.txt");
try {
f.createNewFile();
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
} catch (Exception e) {
e.printStackTrace();
}
}
It creates a new file and provides the below output:
test\..\test.txt
C:\JavaForTesters\test\..\test.txt
C:\JavaForTesters\test.txt
In this case, my assumption is, even though the path provided doesn't exist, because the path contains "/../", java treats this as a relative path and creates the file in the user.dir. So this also makes sense.
But if I update the relative path as below:
#Test
public void testPathConversion() {
File f = new File("test/../../test.txt");
try {
f.createNewFile();
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
} catch (Exception e) {
e.printStackTrace();
}
}
Then I get IOException: Access is denied.
My questions are:
why "test/../test.txt" is treated as a relative path and creates the file in "user.dir" but"test/../../test.txt" returns an error? Where does it attempt to create the file for the path "test/../../test.txt"?
When the specified relative path is not found, the file seems to be created in the user.dir. So, it appears to me that the below two scenarios does the same thing:
//scenario 1
File f = new File("test/../test.txt");
f.createNewFile();
//scenario 2
File f = new File("test.txt");
f.createNewFile();
So is there a real world case where one would use scenario 1 instead of scenario 2?
I suppose I am missing something obvious here or have fundamentally misunderstood relative paths. I went through the Java docs for File and I am not able to find an explanation for this. There are quite a few questions posted in Stack Overflow regarding relative paths, but the ones I looked up were for specific scenarios and not exactly about how relative paths are resolved.
It will be great if someone could please explain me how this works or point to some related links?
There is a concept of a working directory.
This directory is represented by a . (dot).
In relative paths, everything else is relative to it.
Simply put the . (the working directory) is where you run your program.
In some cases the working directory can be changed but in general this is
what the dot represents. I think this is C:\JavaForTesters\ in your case.
So test\..\test.txt means: the sub-directory test
in my working directory, then one level up, then the
file test.txt. This is basically the same as just test.txt.
For more details check here.
http://docs.oracle.com/javase/7/docs/api/java/io/File.html
http://docs.oracle.com/javase/tutorial/essential/io/pathOps.html
When your path starts with a root dir i.e. C:\ in windows or / in Unix or in java resources path, it is considered to be an absolute path. Everything else is relative, so
new File("test.txt") is the same as new File("./test.txt")
new File("test/../test.txt") is the same as new File("./test/../test.txt")
The major difference between getAbsolutePath and getCanonicalPath is that the first one concatenates a parent and a child path, so it may contain dots: .. or .. getCanonicalPath will always return the same path for a particular file.
Note: File.equals uses an abstract form of a path (getAbsolutePath) to compare files, so this means that two File objects for the same might not be equal and Files are unsafe to use in collections like Map or Set.
The working directory is a common concept across virtually all operating systems and program languages etc. It's the directory in which your program is running. This is usually (but not always, there are ways to change it) the directory the application is in.
Relative paths are ones that start without a drive specifier. So in linux they don't start with a /, in windows they don't start with a C:\, etc. These always start from your working directory.
Absolute paths are the ones that start with a drive (or machine for network paths) specifier. They always go from the start of that drive.
Relative paths can be best understood if you know how Java runs the program.
There is a concept of working directory when running programs in Java. Assuming you have a class, say, FileHelper that does the IO under
/User/home/Desktop/projectRoot/src/topLevelPackage/.
Depending on the case where you invoke java to run the program, you will have different working directory. If you run your program from within and IDE, it will most probably be projectRoot.
In this case $ projectRoot/src : java topLevelPackage.FileHelper it will be src.
In this case $ projectRoot : java -cp src topLevelPackage.FileHelper it will be projectRoot.
In this case $ /User/home/Desktop : java -cp ./projectRoot/src topLevelPackage.FileHelper it will be Desktop.
(Assuming $ is your command prompt with standard Unix-like FileSystem. Similar correspondence/parallels with Windows system)
So, your relative path root (.) resolves to your working directory. Thus to be better sure of where to write files, it's said to consider below approach.
package topLevelPackage
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FileHelper {
// Not full implementation, just barebone stub for path
public void createLocalFile() {
// Explicitly get hold of working directory
String workingDir = System.getProperty("user.dir");
Path filePath = Paths.get(workingDir+File.separator+"sampleFile.txt");
// In case we need specific path, traverse that path, rather using . or ..
Path pathToProjectRoot = Paths.get(System.getProperty("user.home"), "Desktop", "projectRoot");
System.out.println(filePath);
System.out.println(pathToProjectRoot);
}
}
Hope this helps.
On windows and Netbeans you can set the relative path as:
new FileReader("src\\PACKAGE_NAME\\FILENAME");
On Linux and Netbeans you can set the relative path as:
new FileReader("src/PACKAGE_NAME/FILENAME");
If you have your code inside Source Packages
I do not know if it is the same for eclipse or other IDE
Only slightly related to the question, but try to wrap your head around this one. So un-intuitive:
import java.nio.file.*;
class Main {
public static void main(String[] args) {
Path p1 = Paths.get("/personal/./photos/./readme.txt");
Path p2 = Paths.get("/personal/index.html");
Path p3 = p1.relativize(p2);
System.out.println(p3); //prints ../../../../index.html !!
}
}
I went off of peter.petrov's answer but let me explain where you make the file edits to change it to a relative path.
Simply edit "AXLAPIService.java" and change
url = new URL("file:C:users..../schema/current/AXLAPI.wsdl");
to
url = new URL("file:./schema/current/AXLAPI.wsdl");
or where ever you want to store it.
You can still work on packaging the wsdl file into the meta-inf folder in the jar but this was the simplest way to get it working for me.

Whether a file is symbolic link or not in Java [duplicate]

In a DirectoryWalker class I want to find out if a File instance is actually a symbolic link to a directory (assuming, the walker walks on UNIX systems). Given, I already know the instance is a directory, would the following be a reliable condition to determine the symbolic link?
File file;
// ...
if (file.getAbsolutePath().equals(file.getCanonicalPath())) {
// real directory ---> do normal stuff
}
else {
// possible symbolic link ---> do link stuff
}
The technique used in Apache Commons uses the canonical path to the parent directory, not the file itself. I don't think that you can guarantee that a mismatch is due to a symbolic link, but it's a good indication that the file needs special treatment.
This is Apache code (subject to their license), modified for compactness.
public static boolean isSymlink(File file) throws IOException {
if (file == null)
throw new NullPointerException("File must not be null");
File canon;
if (file.getParent() == null) {
canon = file;
} else {
File canonDir = file.getParentFile().getCanonicalFile();
canon = new File(canonDir, file.getName());
}
return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
}
Java 1.6 does not provide such low level access to the file system. Looks like NIO 2, which should be included in Java 1.7, will have support for symbolic links. A draft of the new API is available. Symbolic links are mentioned there, creating and following them is possible. I'm not exactly sure that which method should be used to find out whether a file is a symbolic link. There's a mailing list for discussing NIO 2 - maybe they will know.
Also, watch out for file.isFile() and file.isDirectory() both returning results based on the resolved file and therefore both returning false when file refers to a symlink where the target doesn't exist.
(I know this isn't a useful answer in itself but it tripped me up a couple of times so thought I should share)
It looks like getCanonicalPath() can do other things that might make it different from the absolute path.
This method first converts this pathname to absolute form if necessary, as if by invoking the getAbsolutePath() method, and then maps it to its unique form in a system-dependent way. This typically involves removing redundant names such as "." and ".." from the pathname, resolving symbolic links (on UNIX platforms), and converting drive letters to a standard case (on Microsoft Windows platforms).
But it might work for the vast majority of your use cases; your mileage may vary.
If you are already coding something specifically for *nix, then you could do a shell command from Java like this:
Process p = Runtime.getRuntime().exec(new String[]{"test", "-h", yourFileName});
p.waitFor();
if (p.exitValue() == 0)
System.out.println("This file is a symbolic link");
else
System.out.println("This file is not a symbolic link");
That's very specific to *nix, but it does at least work.
Sorry to reply to such an old post, but I was looking for a solution for Windows systems some time back, and some of the previous answers didn't work out for me. If you're not concerned with cross platform compatibility and only need a solution for Windows, the following technique worked well for my purposes.
File f = new File("whatever file or folder");
if (f instanceof ShellFolder) {
ShellFolder sf = (ShellFolder)f;
if (sf.isLink()) {
// Your code when it's a link
}
}
I thought I would share some good fortune I had in dealing with this issue. I am using JDK 1.6.0_23 and so I cannot benefit from NIO2. I am building and running on Windows 7 /x64 ONLY so mileage may vary in other environments. Unfortunately, other solutions here did not work for me in avoiding NullPointerExceptions caused when attempting to traverse a junction (probably because junction != symlink....). While I am not constrained by JDK version, I decided to keep at the problem for a bit longer.
I had this code which would cause a NullPointerException if used on a symbolic link or when encountering the 'System Volume Information' directory. (Note, traverseItem.f() returns an object of type java.io.File)
if (traverseItem.f().isDirectory) {
for (File item : traverseItem.f().listFiles()) {
So, it is supposedly a directory but calling listFiles() on it causes an NPE. What to do? I spied the list() method and wondered if it would exhibit the same behavior. What I discovered was the following:
Calling list() on a File describing an empty folder returns a String[] array of length zero. However, calling list() on a File describing a junction which would otherwise crash from listFiles() returns null
I was able to avoid the NullPointerExceptions by adding the following test before calling listFiles()
String[] contents = traverseItem.f().list();
if (contents != null) { //Non-traversible if null, possibly junction or ???
It remains to exhaustively test all cases of junction, symbolic link, hard link, and dare I mention it, shortcut, but this may help some.

Categories