Last active
March 18, 2024 20:59
-
-
Save rucko24/e7f35deb6f342d39e654bf986e3b7685 to your computer and use it in GitHub Desktop.
A Java watch for a directory, allowing octal mode and user permissions to be changed recursively.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.watcher.watcherdir; | |
import java.io.IOException; | |
import java.nio.file.FileSystems; | |
import java.nio.file.Files; | |
import java.nio.file.Path; | |
import java.nio.file.WatchEvent; | |
import java.nio.file.WatchKey; | |
import java.nio.file.WatchService; | |
import java.nio.file.attribute.PosixFilePermission; | |
import java.nio.file.attribute.PosixFilePermissions; | |
import java.nio.file.attribute.UserPrincipal; | |
import java.nio.file.attribute.UserPrincipalLookupService; | |
import java.util.Set; | |
import java.util.logging.Logger; | |
import java.util.stream.Stream; | |
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; | |
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; | |
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; | |
import static java.nio.file.StandardWatchEventKinds.OVERFLOW; | |
/** | |
* Listening for changes in the <strong>/mnt/pool/movies</strong> dataset | |
* <p> | |
* And if there is a creation event we change the owner to <strong>jellyfin</strong> with the octal mode 775 | |
*/ | |
public class WatchDir { | |
private static final Logger LOGGER = Logger.getLogger(WatchDir.class.getName()); | |
/** | |
* Octal 775 | |
*/ | |
private static final String OCTAL_775 = "rwxrwxr-x"; | |
/** | |
* Octal 770 | |
*/ | |
private static final String OCTAL_770 = "rwxrwx---"; | |
/** | |
* The dataset path to watch, is used with the <strong>-p</strong> parameter | |
*/ | |
private final Path path; | |
/** | |
* The octal mode, is used with the <strong>-o</strong> parameter | |
*/ | |
private final String octal; | |
/** | |
* The user name to apply in this directory, is used with the <strong>-u</strong> parameter | |
*/ | |
private final String userName; | |
public WatchDir(final String userName, final String path, final String octal) { | |
this.userName = userName; | |
this.path = Path.of(path); | |
this.octal = octal; | |
this.watchDirectory(); | |
} | |
@SuppressWarnings("unchecked") | |
private void watchDirectory() { | |
try { | |
WatchService watcher = FileSystems.getDefault().newWatchService(); | |
this.registerAll(path, watcher); | |
WatchKey key; | |
LOGGER.info("Listening in..." + path); | |
for (; ; ) { | |
// wait for key to be signaled | |
try { | |
key = watcher.take(); | |
} catch (InterruptedException x) { | |
return; | |
} | |
for (WatchEvent<?> event : key.pollEvents()) { | |
WatchEvent.Kind<?> kind = event.kind(); | |
if (kind == OVERFLOW) { | |
continue; | |
} | |
WatchEvent<Path> ev = (WatchEvent<Path>) event; | |
Path filename = ev.context(); | |
if (kind == ENTRY_CREATE) { | |
/* | |
* Si pasamos el filename solo se procesara el directorio nuevo. | |
* Si pasamos el path del parametro -p por el filename, procesaremos el directorio completo | |
*/ | |
LOGGER.info("CREATE: " + filename); | |
changePermissionsAndOwnerRecursively(path); | |
} | |
if (kind == ENTRY_DELETE) { | |
LOGGER.info("DELETE: " + filename); | |
changePermissionsAndOwnerRecursively(path); | |
} | |
if (kind == ENTRY_MODIFY) { | |
LOGGER.info("MODIFY: " + filename); | |
changePermissionsAndOwnerRecursively(path); | |
} | |
} | |
boolean valid = key.reset(); | |
if (!valid) { | |
break; | |
} | |
} | |
} catch (IOException x) { | |
LOGGER.severe(x.getMessage()); | |
} | |
} | |
/** | |
* Register the given directory and all its sub-directories with the WatchService. | |
*/ | |
private void registerAll(final Path start, final WatchService watchService) throws IOException { | |
// register directory and sub-directories | |
Files.walkFileTree(start, new SimpleFileVisitor<>() { | |
@Override | |
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) | |
throws IOException { | |
dir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); | |
return FileVisitResult.CONTINUE; | |
} | |
}); | |
} | |
/** | |
* Change permissions recursively | |
* | |
* @param pathParam | |
*/ | |
private void changePermissionsAndOwnerRecursively(Path pathParam) { | |
try (Stream<Path> stream = Files.walk(pathParam, 3)) { // FOLLOW_LINKS | |
stream.forEach(path -> { | |
this.setPermissions(path); | |
this.changeOwner(path); | |
}); | |
LOGGER.info("Owner changed correctly to " + this.userName); | |
LOGGER.info("Permissions changed correctly"); | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
/** | |
* Set octal permissions | |
* | |
* @param path the current dir or a filename | |
* | |
*/ | |
private void setPermissions(final Path path) { | |
try { | |
final String octalMode = this.octal.equals("775") ? OCTAL_775 : OCTAL_770; | |
Set<PosixFilePermission> permissions = PosixFilePermissions.fromString(octalMode); | |
Files.setPosixFilePermissions(path, permissions); | |
} catch (IOException e) { | |
LOGGER.severe(e.getMessage()); | |
} | |
} | |
/** | |
* The user to the directory and files is set up, you must have root permissions to run this. | |
* <p> | |
* The user must exist, otherwise, a <strong>UserPrincipalNotFoundException</strong> | |
* | |
* @param path | |
* @throws IOException | |
*/ | |
private void changeOwner(final Path path) { | |
try { | |
UserPrincipalLookupService lookupService = path.getFileSystem().getUserPrincipalLookupService(); | |
UserPrincipal userPrincipal = lookupService.lookupPrincipalByName(this.userName); | |
Files.setOwner(path, userPrincipal); | |
} catch (IOException ex) { | |
LOGGER.severe("The user "+ this.userName + " does not exist"); | |
LOGGER.severe("leaving now..."); | |
System.exit(0); | |
} | |
} | |
/** | |
* | |
* @param args | |
*/ | |
public static void main(String... args) { | |
System.out.println(""); | |
System.out.println("rubn"); | |
System.out.println("https://rubn0x52.com"); | |
//String[] args = {"-u","rubn","-p","/dir/test-dir/","-o","770"}; | |
if (args.length == 0) { | |
LOGGER.info("No input parameters present"); | |
System.exit(1); | |
} else if (("-h".equals(args[0]) | |
|| "-help".equals(args[0]) | |
|| "--help".equals(args[0]) | |
|| "--h".equals(args[0]))) { | |
LOGGER.info("usage: java -jar watcher.jar -u [--user ex: an existing user] -p [--path ex: path,dir,dataset] -o [--octal mode ex: 775, 770]"); | |
System.exit(1); | |
} else { | |
if (args.length > 3 && args.length <=5) {// valid path args[3] | |
LOGGER.info("Please view usage with --h, -h, -help, --help" ); | |
System.exit(0); | |
} else if(args.length > 3 && args.length <=6) { | |
new WatchDir(args[1].trim(), args[3].trim(), args[5].trim()); | |
} else { | |
LOGGER.info("Please view usage with --h, -h, -help, --help" ); | |
System.exit(0); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment