How do I programmatically change file permissions? - java

In Java, I'm dynamically creating a set of files and I'd like to change the file permissions on these files on a linux/unix file system. I'd like to be able to execute the Java equivalent of chmod. Is that possible Java 5? If so, how?
I know in Java 6 the File object has setReadable()/setWritable() methods. I also know I could make a system call to do this, but I'd like to avoid that if possible.

Full control over file attributes is available in Java 7, as part of the "new" New IO facility (NIO.2). For example, POSIX permissions can be set on an existing file with setPosixFilePermissions(), or atomically at file creation with methods like createFile() or newByteChannel().
You can create a set of permissions using EnumSet.of(), but the helper method PosixFilePermissions.fromString() will uses a conventional format that will be more readable to many developers. For APIs that accept a FileAttribute, you can wrap the set of permissions with with PosixFilePermissions.asFileAttribute().
Set<PosixFilePermission> ownerWritable = PosixFilePermissions.fromString("rw-r--r--");
FileAttribute<?> permissions = PosixFilePermissions.asFileAttribute(ownerWritable);
Files.createFile(path, permissions);
In earlier versions of Java, using native code of your own, or exec-ing command-line utilities are common approaches.

Prior to Java 6, there is no support of file permission update at Java level. You have to implement your own native method or call Runtime.exec() to execute OS level command such as chmod.
Starting from Java 6, you can useFile.setReadable()/File.setWritable()/File.setExecutable() to set file permissions. But it doesn't simulate the POSIX file system which allows to set permission for different users. File.setXXX() only allows to set permission for owner and everyone else.
Starting from Java 7, POSIX file permission is introduced. You can set file permissions like what you have done on *nix systems. The syntax is :
File file = new File("file4.txt");
file.createNewFile();
Set<PosixFilePermission> perms = new HashSet<>();
perms.add(PosixFilePermission.OWNER_READ);
perms.add(PosixFilePermission.OWNER_WRITE);
Files.setPosixFilePermissions(file.toPath(), perms);
This method can only be used on POSIX file system, this means you cannot call it on Windows system.
For details on file permission management, recommend you to read this post.

In addition to erickson's suggestions, there's also jna, which allows you to call native libraries without using jni. It's shockingly easy to use, and I've used it on a couple of projects with great success.
The only caveat is that it's slower than jni, so if you're doing this to a very large number of files that might be an issue for you.
(Editing to add example)
Here's a complete jna chmod example:
import com.sun.jna.Library;
import com.sun.jna.Native;
public class Main {
private static CLibrary libc = (CLibrary) Native.loadLibrary("c", CLibrary.class);
public static void main(String[] args) {
libc.chmod("/path/to/file", 0755);
}
}
interface CLibrary extends Library {
public int chmod(String path, int mode);
}

For Windows 7 with NIO 2:
public static void main(String[] args) throws IOException {
Path file = Paths.get("c:/touch.txt");
AclFileAttributeView aclAttr = Files.getFileAttributeView(file, AclFileAttributeView.class);
System.out.println(aclAttr.getOwner());
for (AclEntry aclEntry : aclAttr.getAcl()) {
System.out.println(aclEntry);
}
System.out.println();
UserPrincipalLookupService upls = file.getFileSystem().getUserPrincipalLookupService();
UserPrincipal user = upls.lookupPrincipalByName(System.getProperty("user.name"));
AclEntry.Builder builder = AclEntry.newBuilder();
builder.setPermissions( EnumSet.of(AclEntryPermission.READ_DATA, AclEntryPermission.EXECUTE,
AclEntryPermission.READ_ACL, AclEntryPermission.READ_ATTRIBUTES, AclEntryPermission.READ_NAMED_ATTRS,
AclEntryPermission.WRITE_ACL, AclEntryPermission.DELETE
));
builder.setPrincipal(user);
builder.setType(AclEntryType.ALLOW);
aclAttr.setAcl(Collections.singletonList(builder.build()));
}

Just to update this answer unless anyone comes across this later, since JDK 6 you can use
File file = new File('/directory/to/file');
file.setWritable(boolean);
file.setReadable(boolean);
file.setExecutable(boolean);
you can find the documentation on Oracle File(Java Platform SE 7). Bear in mind that these commands only work if the current working user has ownership or write access to that file. I am aware that OP wanted chmod type access for more intricate user configuration. these will set the option across the board for all users.

If you want to set 777 permission to your created file than you can use the following method:
public void setPermission(File file) throws IOException{
Set<PosixFilePermission> perms = new HashSet<>();
perms.add(PosixFilePermission.OWNER_READ);
perms.add(PosixFilePermission.OWNER_WRITE);
perms.add(PosixFilePermission.OWNER_EXECUTE);
perms.add(PosixFilePermission.OTHERS_READ);
perms.add(PosixFilePermission.OTHERS_WRITE);
perms.add(PosixFilePermission.OTHERS_EXECUTE);
perms.add(PosixFilePermission.GROUP_READ);
perms.add(PosixFilePermission.GROUP_WRITE);
perms.add(PosixFilePermission.GROUP_EXECUTE);
Files.setPosixFilePermissions(file.toPath(), perms);
}

You can use the methods of the File class:
http://docs.oracle.com/javase/7/docs/api/java/io/File.html

Apache ant chmod (not very elegant, adding it for completeness) credit shared with #msorsky
Chmod chmod = new Chmod();
chmod.setProject(new Project());
FileSet mySet = new FileSet();
mySet.setDir(new File("/my/path"));
mySet.setIncludes("**");
chmod.addFileset(mySet);
chmod.setPerm("+w");
chmod.setType(new FileDirBoth());
chmod.execute();

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.Set;
public class FileAndDirectory1 {
public static void main(String[] args) {
File file = new File("fileTest1.txt");
System.out.println(file.getAbsoluteFile());
try {
//file.createNewFile();
if(!file.exists())
{
//PosixFilePermission is an enum class, PosixFilePermissions is a final class
//create file permissions from string
Set<PosixFilePermission> filePermissions = PosixFilePermissions.fromString("---------"/* "rwxrwxrwx" */);
FileAttribute<?> permissions = PosixFilePermissions.asFileAttribute(filePermissions);
Files.createFile(file.toPath(), permissions);
// printing the permissions associated with the file
System.out.println("Executable: " + file.canExecute());
System.out.println("Readable: " + file.canRead());
System.out.println("Writable: "+ file.canWrite());
file.setExecutable(true);
file.setReadable(true);
file.setWritable(true);
}
else
{
//modify permissions
//get the permission using file attributes
Set<PosixFilePermission> perms = Files.readAttributes(file.toPath(), PosixFileAttributes.class).permissions();
perms.remove(PosixFilePermission.OWNER_WRITE);
perms.add(PosixFilePermission.OWNER_READ);
perms.add(PosixFilePermission.OWNER_EXECUTE);
perms.add(PosixFilePermission.GROUP_WRITE);
perms.add(PosixFilePermission.GROUP_READ);
perms.add(PosixFilePermission.GROUP_EXECUTE);
perms.add(PosixFilePermission.OTHERS_WRITE);
perms.add(PosixFilePermission.OTHERS_READ);
perms.add(PosixFilePermission.OTHERS_EXECUTE);
Files.setPosixFilePermissions(file.toPath(), perms);
System.out.println("Executable: " + file.canExecute());
System.out.println("Readable: " + file.canRead());
System.out.println("Writable: "+ file.canWrite());
file.delete();
}
} catch (IOException e) {
e.printStackTrace();
}
Path path = Paths.get(String.valueOf(file));
System.out.println(path);
}
}

for Oralce Java 6:
private static int chmod(String filename, int mode) {
try {
Class<?> fspClass = Class.forName("java.util.prefs.FileSystemPreferences");
Method chmodMethod = fspClass.getDeclaredMethod("chmod", String.class, Integer.TYPE);
chmodMethod.setAccessible(true);
return (Integer)chmodMethod.invoke(null, filename, mode);
} catch (Throwable ex) {
return -1;
}
}
works under solaris/linux.

There is an example class on Oracle Docs which works very much similar to the UNIX chmod. It works with java se 7+ though.

Permission 777 is the same as rwxrwxrwx which you can set as follows:
Files.setPosixFilePermissions(path, PosixFilePermissions.fromString("rwxrwxrwx"))

Related

Java add Classpaths at runtime

There are many answers to this question in the stackoverflow?
But the most cast the ClassLoader.getSystemClassLoader() to URLClassLoader and this works anymore.
The classes must be found by the systemclassloader.
Is there an another solution?
- without restarting the jar
- without creating a own classloader (In this case I must replace the systemclassloader with my own)
The missing classes/jars must be added at the moment only on startup and I didn't want to add these in the manifest with "Classpath".
I found the Java Agent with the premain-Method. This can also work great, but in this case I want to start the premain method without calling "java -javaagent:... -jar ..."
Currently I restart my programm at the beginning with the missing classpaths:
public class LibLoader {
protected static List<File> files = new LinkedList<>();
public static void add(File file) {
files.add(file);
}
public static boolean containsLibraries() {
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
String[] classpaths = runtimeMxBean.getClassPath().split(System.getProperty("path.separator"));
List<File> classpathfiles = new LinkedList<>();
for(String string : classpaths) classpathfiles.add(new File(string));
for(File file : files) {
if(!classpathfiles.contains(file)) return false;
}
return true;
}
public static String getNewClassPaths() {
StringBuilder builder = new StringBuilder();
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
builder.append(runtimeMxBean.getClassPath());
for(File file : files) {
if(builder.length() > 0) builder.append(System.getProperty("path.separator"));
builder.append(file.getAbsolutePath());
}
return builder.toString();
}
public static boolean restartWithLibrary(Class<?> main, String[] args) throws IOException {
if(containsLibraries()) return false;
List<String> runc = new LinkedList<>();
runc.add(System.getProperty("java.home") + "\\bin\\javaw.exe");
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
List<String> arguments = runtimeMxBean.getInputArguments();
runc.addAll(arguments);
File me = new File(LibLoader.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String classpaths = getNewClassPaths();
if(!classpaths.isEmpty()) {
runc.add("-cp");
runc.add(classpaths);
}
if(me.isFile()) {
runc.add("-jar");
runc.add(me.getAbsolutePath().replace("%20", " "));
} else {
runc.add(main.getName());
}
for(String arg : args) runc.add(arg);
ProcessBuilder processBuilder = new ProcessBuilder(runc);
processBuilder.directory(new File("."));
processBuilder.redirectOutput(Redirect.INHERIT);
processBuilder.redirectError(Redirect.INHERIT);
processBuilder.redirectInput(Redirect.INHERIT);
Process process = processBuilder.start();
try {
process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
}
Hope someone has a better solution.
Problem is, the classes must be found my the system ClassLoader not by a new ClassLoader.
It sound like your current solution of relaunching the JVM is the only clean way to do it.
The system ClassLoader cannot be changed, and you cannot add extra JARs to it at runtime.
(If you tried to use reflection to mess with the system classloader's data structures, at best it will be non-portable and version dependent. At worst it will be either error prone ... or blocked by the JVM's runtime security mechanisms.)
The solution suggested by Johannes Kuhn in a comment won't work. The java.system.class.loader property is consulted during JVM bootstrap. By the time your application is running, making changes to it will have no effect. I am not convinced that the approach in his Answer would work either.
Here is one possible alternative way to handle this ... if you can work out what the missing JARs are early enough.
Write yourself a Launcher class that does the following:
Save the command line arguments
Find the application JAR file
Extract the Main-Class and Class-Path attributes from the MANIFEST.MF.
Work out what the real classpath should be based on the above ... and other application specific logic.
Create a new URLClassLoader with the correct classpath, and the system classloader as its parent.
Use it to load the main class.
Use reflection to find the main classes main method.
Call it passing the save command line arguments.
This is essentially the approach that Spring Bootstrap and OneJar (and other things) take to handle the "jars in a jar" problem and so on. It avoids launching 2 VMs.

Basic Java Runtime program cannot find python

Hello working on a small program that just needs to run a python script I have. This python script will play a given .wav file, and draw a shape on the turtle screen. As such, I'm not looking for an output to be returned to java. Here is my java code:
public class Driver {
public static void main(String[] args){
try {
Process p = Runtime.getRuntime().exec("python " +
" D:/Coding Files/Python/MusicColors.py" +" teenagers.wav");
}
catch (Exception e){
System.out.println(e);
}
}
}
The exception I get is:
java.io.IOException: Cannot run program "python":
CreateProcess error=2, The system cannot find the file specified
I probably am making a very stupid mistake as I have limited knowledge in the subject of processes and such. I added python to my system path, so whenever I put "python" into command line, it returns with
Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:01:18) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
And makes it the python shell.
Here is the exact line I added to my environment path:
C:\Users\Joe\AppData\Local\Programs\Python\Python35-32
If anyone can figure out where I went wrong I'd really appreciate it!
The $PATH variable you've set is not inherited in Java's execution context. Try passing the Python's bin path to exec()'s execution environment.
To do this, the code below first retrieve all the environment variables and create an array of ENV_KEY=ENV_VALUE pairs.
Then, the path to your Python's bin is appended to the PATH value.
Finally, we pass the array of all environment variables to exec() (via the second parameter).
import java.util.HashMap;
import java.util.Map;
public class Driver {
public static void main(String[] args){
try {
String[] commands = {"python D:/Coding Files/Python/MusicColors.py teenagers.wav"};
// Get a list of all environment variables
final Map<String, String> envMap = new HashMap<String, String>(System.getenv());
// Append Python bin path to Path
envMap.put("Path", envMap.get("Path") + ";C:/Users/Joe/AppData/Local/Programs/Python/Python35-32");
// Convert to an array of ENV_KEY=ENV_VALUE format strings
final String[] envs = new String[envMap.size()];
int i = 0;
for (Map.Entry<String, String> e : envMap.entrySet()) {
envs[i] = e.getKey() + '=' + e.getValue();
i++;
}
// Exec with the environment variables
Process p = Runtime.getRuntime().exec(commands, envs);
}
catch (Exception e){
System.out.println(e);
}
}
}

directory not created in ubuntu using java [duplicate]

In Java, I'm dynamically creating a set of files and I'd like to change the file permissions on these files on a linux/unix file system. I'd like to be able to execute the Java equivalent of chmod. Is that possible Java 5? If so, how?
I know in Java 6 the File object has setReadable()/setWritable() methods. I also know I could make a system call to do this, but I'd like to avoid that if possible.
Full control over file attributes is available in Java 7, as part of the "new" New IO facility (NIO.2). For example, POSIX permissions can be set on an existing file with setPosixFilePermissions(), or atomically at file creation with methods like createFile() or newByteChannel().
You can create a set of permissions using EnumSet.of(), but the helper method PosixFilePermissions.fromString() will uses a conventional format that will be more readable to many developers. For APIs that accept a FileAttribute, you can wrap the set of permissions with with PosixFilePermissions.asFileAttribute().
Set<PosixFilePermission> ownerWritable = PosixFilePermissions.fromString("rw-r--r--");
FileAttribute<?> permissions = PosixFilePermissions.asFileAttribute(ownerWritable);
Files.createFile(path, permissions);
In earlier versions of Java, using native code of your own, or exec-ing command-line utilities are common approaches.
Prior to Java 6, there is no support of file permission update at Java level. You have to implement your own native method or call Runtime.exec() to execute OS level command such as chmod.
Starting from Java 6, you can useFile.setReadable()/File.setWritable()/File.setExecutable() to set file permissions. But it doesn't simulate the POSIX file system which allows to set permission for different users. File.setXXX() only allows to set permission for owner and everyone else.
Starting from Java 7, POSIX file permission is introduced. You can set file permissions like what you have done on *nix systems. The syntax is :
File file = new File("file4.txt");
file.createNewFile();
Set<PosixFilePermission> perms = new HashSet<>();
perms.add(PosixFilePermission.OWNER_READ);
perms.add(PosixFilePermission.OWNER_WRITE);
Files.setPosixFilePermissions(file.toPath(), perms);
This method can only be used on POSIX file system, this means you cannot call it on Windows system.
For details on file permission management, recommend you to read this post.
In addition to erickson's suggestions, there's also jna, which allows you to call native libraries without using jni. It's shockingly easy to use, and I've used it on a couple of projects with great success.
The only caveat is that it's slower than jni, so if you're doing this to a very large number of files that might be an issue for you.
(Editing to add example)
Here's a complete jna chmod example:
import com.sun.jna.Library;
import com.sun.jna.Native;
public class Main {
private static CLibrary libc = (CLibrary) Native.loadLibrary("c", CLibrary.class);
public static void main(String[] args) {
libc.chmod("/path/to/file", 0755);
}
}
interface CLibrary extends Library {
public int chmod(String path, int mode);
}
For Windows 7 with NIO 2:
public static void main(String[] args) throws IOException {
Path file = Paths.get("c:/touch.txt");
AclFileAttributeView aclAttr = Files.getFileAttributeView(file, AclFileAttributeView.class);
System.out.println(aclAttr.getOwner());
for (AclEntry aclEntry : aclAttr.getAcl()) {
System.out.println(aclEntry);
}
System.out.println();
UserPrincipalLookupService upls = file.getFileSystem().getUserPrincipalLookupService();
UserPrincipal user = upls.lookupPrincipalByName(System.getProperty("user.name"));
AclEntry.Builder builder = AclEntry.newBuilder();
builder.setPermissions( EnumSet.of(AclEntryPermission.READ_DATA, AclEntryPermission.EXECUTE,
AclEntryPermission.READ_ACL, AclEntryPermission.READ_ATTRIBUTES, AclEntryPermission.READ_NAMED_ATTRS,
AclEntryPermission.WRITE_ACL, AclEntryPermission.DELETE
));
builder.setPrincipal(user);
builder.setType(AclEntryType.ALLOW);
aclAttr.setAcl(Collections.singletonList(builder.build()));
}
Just to update this answer unless anyone comes across this later, since JDK 6 you can use
File file = new File('/directory/to/file');
file.setWritable(boolean);
file.setReadable(boolean);
file.setExecutable(boolean);
you can find the documentation on Oracle File(Java Platform SE 7). Bear in mind that these commands only work if the current working user has ownership or write access to that file. I am aware that OP wanted chmod type access for more intricate user configuration. these will set the option across the board for all users.
If you want to set 777 permission to your created file than you can use the following method:
public void setPermission(File file) throws IOException{
Set<PosixFilePermission> perms = new HashSet<>();
perms.add(PosixFilePermission.OWNER_READ);
perms.add(PosixFilePermission.OWNER_WRITE);
perms.add(PosixFilePermission.OWNER_EXECUTE);
perms.add(PosixFilePermission.OTHERS_READ);
perms.add(PosixFilePermission.OTHERS_WRITE);
perms.add(PosixFilePermission.OTHERS_EXECUTE);
perms.add(PosixFilePermission.GROUP_READ);
perms.add(PosixFilePermission.GROUP_WRITE);
perms.add(PosixFilePermission.GROUP_EXECUTE);
Files.setPosixFilePermissions(file.toPath(), perms);
}
You can use the methods of the File class:
http://docs.oracle.com/javase/7/docs/api/java/io/File.html
Apache ant chmod (not very elegant, adding it for completeness) credit shared with #msorsky
Chmod chmod = new Chmod();
chmod.setProject(new Project());
FileSet mySet = new FileSet();
mySet.setDir(new File("/my/path"));
mySet.setIncludes("**");
chmod.addFileset(mySet);
chmod.setPerm("+w");
chmod.setType(new FileDirBoth());
chmod.execute();
for Oralce Java 6:
private static int chmod(String filename, int mode) {
try {
Class<?> fspClass = Class.forName("java.util.prefs.FileSystemPreferences");
Method chmodMethod = fspClass.getDeclaredMethod("chmod", String.class, Integer.TYPE);
chmodMethod.setAccessible(true);
return (Integer)chmodMethod.invoke(null, filename, mode);
} catch (Throwable ex) {
return -1;
}
}
works under solaris/linux.
There is an example class on Oracle Docs which works very much similar to the UNIX chmod. It works with java se 7+ though.
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.Set;
public class FileAndDirectory1 {
public static void main(String[] args) {
File file = new File("fileTest1.txt");
System.out.println(file.getAbsoluteFile());
try {
//file.createNewFile();
if(!file.exists())
{
//PosixFilePermission is an enum class, PosixFilePermissions is a final class
//create file permissions from string
Set<PosixFilePermission> filePermissions = PosixFilePermissions.fromString("---------"/* "rwxrwxrwx" */);
FileAttribute<?> permissions = PosixFilePermissions.asFileAttribute(filePermissions);
Files.createFile(file.toPath(), permissions);
// printing the permissions associated with the file
System.out.println("Executable: " + file.canExecute());
System.out.println("Readable: " + file.canRead());
System.out.println("Writable: "+ file.canWrite());
file.setExecutable(true);
file.setReadable(true);
file.setWritable(true);
}
else
{
//modify permissions
//get the permission using file attributes
Set<PosixFilePermission> perms = Files.readAttributes(file.toPath(), PosixFileAttributes.class).permissions();
perms.remove(PosixFilePermission.OWNER_WRITE);
perms.add(PosixFilePermission.OWNER_READ);
perms.add(PosixFilePermission.OWNER_EXECUTE);
perms.add(PosixFilePermission.GROUP_WRITE);
perms.add(PosixFilePermission.GROUP_READ);
perms.add(PosixFilePermission.GROUP_EXECUTE);
perms.add(PosixFilePermission.OTHERS_WRITE);
perms.add(PosixFilePermission.OTHERS_READ);
perms.add(PosixFilePermission.OTHERS_EXECUTE);
Files.setPosixFilePermissions(file.toPath(), perms);
System.out.println("Executable: " + file.canExecute());
System.out.println("Readable: " + file.canRead());
System.out.println("Writable: "+ file.canWrite());
file.delete();
}
} catch (IOException e) {
e.printStackTrace();
}
Path path = Paths.get(String.valueOf(file));
System.out.println(path);
}
}
Permission 777 is the same as rwxrwxrwx which you can set as follows:
Files.setPosixFilePermissions(path, PosixFilePermissions.fromString("rwxrwxrwx"))

Determine whether a file is a junction (in Windows) or not?

I've been searching around trying to find a way to determine if a file is a junction or not, and have not found any satisfactory answers.
First thing I tried was:
Files.isSymbolicLink(aPath)
It detects only symbolic links not the files referred to as junctions in Windows.
Also tried the solution proposed here (using JNA library):
Stackoverflow question (3249117)
, but it never returned true on any of the files I know to be junctions.
The only way I've found to determine which files are junctions is the following command run in windows command prompt:
DIR /S /A:L
On my computer it returns 66 folders, wheras Files.isSymbolicLink(aPath) returned only 2.
So I suppose I could find a way to utilize this, but I don't think it would be very effiecient when traversing a filetree.
Is there any way to do this using the standard java library, or alternativly JNA?
There can be a way to do it without JNA, if you have the right java, such as Oracle jdk 8. It's dodgy, it can cease to work, but....
You can get BasicFileAttributes interface related to the link:
BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
It can happen that this interface implementation is a class
sun.nio.fs.WindowsFileAttributes. And this class has a method isReparsePoint, which returns true for both junction points and symbolic links. So you can try to use reflection and call the method:
boolean isReparsePoint = false;
if (DosFileAttributes.class.isInstance(attr))
try {
Method m = attr.getClass().getDeclaredMethod("isReparsePoint");
m.setAccessible(true);
isReparsePoint = (boolean) m.invoke(attr);
} catch (Exception e) {
// just gave it a try
}
Now you only can discover whether it really is symbolic link: Files.isSymbolicLink(path)
If its not, but it is reparse point, then that's junction.
If you can write native code in JNA, you can directly call the Win32 API GetFileAttributes() function and check for the FILE_ATTRIBUTE_REPARSE_POINT flag (junctions are implemented as reparse points).
Update: To differentiate between different types of reparse points, you have to retreive the ReparseTag of the actual reparse point. For a junction point, it will be set to IO_REPARSE_TAG_MOUNT_POINT (0xA0000003).
There are two ways to retreive the ReparseTag:
Use DeviceIoControl() with the FSCTL_GET_REPARSE_POINT control code to obtain an REPARSE_DATA_BUFFER struct, which as a ReparseTag field. You can see an example of an IsDirectoryJunction() implementation using this technique in the following article:
NTFS Hard Links, Directory Junctions, and Windows Shortcuts
Use FindFirstFile() to obtain a WIN32_FIND_DATA struct. If the path has the FILE_ATTRIBUTE_REPARSE_POINT attribute, the dwReserved0 field will contain the ReparseTag.
With J2SE 1.7 use Java NIO
/**
* returns true if the Path is a Windows Junction
*/
private static boolean isJunction(Path p) {
boolean isJunction = false;
try {
isJunction = (p.compareTo(p.toRealPath()) != 0);
} catch (IOException e) {
e.printStackTrace(); // TODO: handleMeProperly
}
return isJunction;
}
While on Windows a junction's attributes have isSymbolicLink() == false, they have isOther() == true. So you could do something like:
boolean isWindows = System.getProperty("os.name").toLowerCase().contains("windows")
BasicFileAttributes attrs = Files.readAttributes(aPath, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
boolean isJunction = isWindows && attrs.isDirectory() && attrs.isOther();
Black-Box Solution:
aPath.toRealPath() resolves junctions and symbolic links, so the result will deviate from aPath.
In addition BasicFileAttributes.isSymbolicLink() delivers false for junctions for non-documented reason:
E.g. Path.toRealPath(LinkOption.NOFOLLOW_LINKS) well treats a junction as link an does not resolve it!!
So by non-identity of toRealPath() and BasicFileAttributes.isSymbolicLink() you may identify a junction.
You can discover the link type with PowerShell with the command
(Get-Item -Path fileName -Force).LinkType
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
class WindowsFileLinkUtils {
public enum WindowsLinkType {
JUNCTION("Junction"),
HARD_LINK("HardLink"),
SYMBOLIC_LINK("SymbolicLink");
private final String key;
WindowsLinkType(String key) {
this.key = key;
}
public String getKey() {
return key;
}
}
private static final String CREATE_JUNCTION_COMMAND = "(Get-Item -Path %s -Force).LinkType";
public static Optional<WindowsLinkType> getLinkType(Path path) throws IOException, InterruptedException {
ProcessBuilder processBuilder = createIsJunctionProcessBuilder(path);
Process process = processBuilder.start();
process.waitFor();
try (BufferedReader inStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String output = inStreamReader.readLine();
return Arrays.stream(WindowsLinkType.values()).filter(windowsLinkType -> windowsLinkType.getKey().equals(output)).findFirst();
}
}
private static ProcessBuilder createIsJunctionProcessBuilder(Path target) {
ProcessBuilder processBuilder = new ProcessBuilder();
List<String> arguments = processBuilder.command();
arguments.add("powershell.exe");
arguments.add(String.format(CREATE_JUNCTION_COMMAND, target.toString()));
return processBuilder;
}
private WindowsFileLinkUtils() {
}
}

Can Java launch the Windows UAC?

As the title says, I'm wondering if it is possible for a program written in Java (and only java) to relaunch himself (preferably a .jar) with administrator privileges, showing in the way the native Windows UAC (in order to make it more trustable for the user), i did my homework and found out that it is possible to accomplish this using bridges between c++ and java, but i would really like to do this as a pure java project.
P.S: In the remote case that this result to be impossible, can someone show me the "easy" way to do this using another language (i mean, I've found tutorials, but they are to complicated for something I think it should not be that complicated).
P.S2: In case it is possible to accomplish this, would it work, on other platforms (OS X, Linux)
It cannot be done in pure java.
Best bet would be to write this to a file:
#echo Set objShell = CreateObject("Shell.Application") > %temp%\sudo.tmp.vbs
#echo args = Right("%*", (Len("%*") - Len("%1"))) >> %temp%\sudo.tmp.vbs
#echo objShell.ShellExecute "%1", args, "", "runas" >> %temp%\sudo.tmp.vbs
#cscript %temp%\sudo.tmp.vbs
and save it as something.bat in Windows temp directory (as we have access to this).
You would then execute this from your application using Runtime or ProcessBuilder and exit your application (System.exit(0);).
You should add an immediate start up check to your application that checks if the program has elevation, if it has proceed if not re-run the batch and exit.
Here is an example I made (this must be run when compiled as a Jar or it wont work):
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import javax.swing.JOptionPane;
/**
*
* #author David
*/
public class UacTest {
public static String jarName = "UacTest.jar", batName = "elevate.bat";
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
if (checkForUac()) {//uac is on
JOptionPane.showMessageDialog(null, "I am not elevated");
//attempt elevation
new UacTest().elevate();
System.exit(0);
} else {//uac is not on
//if we get here we are elevated
JOptionPane.showMessageDialog(null, "I am elevated");
}
}
private static boolean checkForUac() {
File dummyFile = new File("c:/aaa.txt");
dummyFile.deleteOnExit();
try {
//attempt to craete file in c:/
try (FileWriter fw = new FileWriter(dummyFile, true)) {
}
} catch (IOException ex) {//we cannot UAC muts be on
//ex.printStackTrace();
return true;
}
return false;
}
private void elevate() {
//create batch file in temporary directory as we have access to it regardless of UAC on or off
File file = new File(System.getProperty("java.io.tmpdir") + "/" + batName);
file.deleteOnExit();
createBatchFile(file);
runBatchFile();
}
private String getJarLocation() {
return getClass().getProtectionDomain().getCodeSource().getLocation().getPath().substring(1);
}
private void runBatchFile() {
//JOptionPane.showMessageDialog(null, getJarLocation());
Runtime runtime = Runtime.getRuntime();
String[] cmd = new String[]{"cmd.exe", "/C",
System.getProperty("java.io.tmpdir") + "/" + batName + " java -jar " + getJarLocation()};
try {
Process proc = runtime.exec(cmd);
//proc.waitFor();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void createBatchFile(File file) {
try {
try (FileWriter fw = new FileWriter(file, true)) {
fw.write(
"#echo Set objShell = CreateObject(\"Shell.Application\") > %temp%\\sudo.tmp.vbs\r\n"
+ "#echo args = Right(\"%*\", (Len(\"%*\") - Len(\"%1\"))) >> %temp%\\sudo.tmp.vbs\r\n"
+ "#echo objShell.ShellExecute \"%1\", args, \"\", \"runas\" >> %temp%\\sudo.tmp.vbs\r\n"
+ "#cscript %temp%\\sudo.tmp.vbs\r\n"
+ "del /f %temp%\\sudo.tmp.vbs\r\n");
}
} catch (IOException ex) {
//ex.printStackTrace();
}
}
}
Use a batch file and the runas command.
I doubt "only Java". At best you would have to have a JNI wrapper around the MSFT module. Unless just invoking the exe using ProcessBuilder counts as "only Java" -- your code to bring up the user console would be only Java but not what it invokes. IOW, Win does not come with a Java API
To relaunch your application elevated, you have to call ShellExecute or ShellExecuteEx function from Windows API and use runas verb.
You can use these API in pure Java with JNA library.
To relaunch yourself, you would have to know the full path to java.exe or javaw.exe, the command-line parameters (class path, if any, and the path to your jar). Obviously you can get this information by using Windows API.
What do you mean by remote case?
You cannot start remote elevated process this way.
You can re-launch your application elevated from a network share. Yet it won't work with mapped drives: after elevation there's no access to user's mapped drives.
No, this can't work on other platforms. UAC is a Windows feature. It's similar to sudo in Linux in some ways, so for Linux you can use sudo $pathtojava/java.exe <yourparameters>. However this won't work nicely if your application is not started from a console. Window Managers usually have wrappers which prompt for password in a GUI dialog.
Just do this with Hackaprofaw (v29). Also it was released in 2002 and started development in 1997 soooooo ye. in 2021 its on version 29.10.7 but-
if raw ram = 0
disable "featureII" program = "JAVA(math = any)"
run on "Hackaprofaw (math = v29(x))
when "featureII" disabled
end

Categories

Resources