3333import java .security .SecureRandom ;
3434import java .util .*;
3535import java .util .concurrent .TimeUnit ;
36+ import java .util .regex .Matcher ;
37+ import java .util .regex .Pattern ;
3638
3739/**
3840 * <p>
@@ -2077,20 +2079,7 @@ class ForJnaPosixEnvironment implements Dispatcher {
20772079 */
20782080 private final PosixLibrary library ;
20792081
2080- /**
2081- * The maximum amount of attempts for checking the result of a foreign process.
2082- */
2083- private final int attempts ;
2084-
2085- /**
2086- * The pause between two checks for another process to return.
2087- */
2088- private final long pause ;
2089-
2090- /**
2091- * The time unit of the pause time.
2092- */
2093- private final TimeUnit timeUnit ;
2082+ private final PosixOwner posixOwner ;
20942083
20952084 /**
20962085 * Creates a new connector for a POSIX enviornment using JNA.
@@ -2101,9 +2090,13 @@ class ForJnaPosixEnvironment implements Dispatcher {
21012090 */
21022091 @ SuppressWarnings ("deprecation" )
21032092 public ForJnaPosixEnvironment (int attempts , long pause , TimeUnit timeUnit ) {
2104- this .attempts = attempts ;
2105- this .pause = pause ;
2106- this .timeUnit = timeUnit ;
2093+ if (Platform .isMac ()) {
2094+ posixOwner = new PosixOwner .ForMacEnvironment (attempts , pause , timeUnit );
2095+ } else if (Platform .isAIX ()) {
2096+ posixOwner = new PosixOwner .ForAixEnvironment (attempts , pause , timeUnit );
2097+ } else {
2098+ posixOwner = new PosixOwner .ForLinuxEnvironment (attempts , pause , timeUnit );
2099+ }
21072100 library = Native .loadLibrary ("c" , PosixLibrary .class );
21082101 }
21092102
@@ -2147,40 +2140,7 @@ public boolean isExistingProcess(int processId) {
21472140 */
21482141 @ SuppressFBWarnings (value = "OS_OPEN_STREAM" , justification = "The stream life-cycle is bound to its process." )
21492142 public int getOwnerIdOf (File file ) {
2150- try {
2151- // The binding for 'stat' is very platform dependant. To avoid the complexity of binding the correct method,
2152- // stat is called as a separate command. This is less efficient but more portable.
2153- Process process = Runtime .getRuntime ().exec (new String []{"stat" ,
2154- Platform .isMac () ? "-f" : "-c" ,
2155- "%u" ,
2156- file .getAbsolutePath ()});
2157- int attempts = this .attempts ;
2158- boolean exited = false ;
2159- String line = new BufferedReader (new InputStreamReader (process .getInputStream (), "UTF-8" )).readLine ();
2160- do {
2161- try {
2162- if (process .exitValue () != 0 ) {
2163- throw new IllegalStateException ("Error while executing stat" );
2164- }
2165- exited = true ;
2166- break ;
2167- } catch (IllegalThreadStateException ignored ) {
2168- try {
2169- Thread .sleep (timeUnit .toMillis (pause ));
2170- } catch (InterruptedException exception ) {
2171- Thread .currentThread ().interrupt ();
2172- throw new IllegalStateException (exception );
2173- }
2174- }
2175- } while (--attempts > 0 );
2176- if (!exited ) {
2177- process .destroy ();
2178- throw new IllegalStateException ("Command for stat did not exit in time" );
2179- }
2180- return Integer .parseInt (line );
2181- } catch (IOException exception ) {
2182- throw new IllegalStateException ("Unable to execute stat command" , exception );
2183- }
2143+ return posixOwner .getOwnerIdOf (file );
21842144 }
21852145
21862146 /**
@@ -2385,6 +2345,249 @@ protected List<String> getFieldOrder() {
23852345 }
23862346 }
23872347 }
2348+
2349+ protected interface PosixOwner {
2350+ /**
2351+ * Returns the user id of the owner of the supplied file.
2352+ *
2353+ * @param file The file for which to locate the owner.
2354+ * @return The owner id of the supplied file.
2355+ */
2356+ int getOwnerIdOf (File file );
2357+
2358+ class ForLinuxEnvironment implements PosixOwner {
2359+
2360+ /**
2361+ * The maximum amount of attempts for checking the result of a foreign process.
2362+ */
2363+ private final int attempts ;
2364+
2365+ /**
2366+ * The pause between two checks for another process to return.
2367+ */
2368+ private final long pause ;
2369+
2370+ /**
2371+ * The time unit of the pause time.
2372+ */
2373+ private final TimeUnit timeUnit ;
2374+
2375+ /**
2376+ * Creates a new connector for a Linux POSIX enviornment using stat.
2377+ *
2378+ * @param attempts The maximum amount of attempts for checking the result of a foreign process.
2379+ * @param pause The pause between two checks for another process to return.
2380+ * @param timeUnit The time unit of the pause time.
2381+ */
2382+ public ForLinuxEnvironment (int attempts , long pause , TimeUnit timeUnit ) {
2383+ this .attempts = attempts ;
2384+ this .pause = pause ;
2385+ this .timeUnit = timeUnit ;
2386+ }
2387+
2388+ /**
2389+ * Returns the user id of the owner of the supplied file.
2390+ *
2391+ * @param file The file for which to locate the owner.
2392+ * @return The owner id of the supplied file.
2393+ */
2394+ @ Override
2395+ public int getOwnerIdOf (File file ) {
2396+ try {
2397+ // The binding for 'stat' is very platform dependant. To avoid the complexity of binding the correct method,
2398+ // stat is called as a separate command. This is less efficient but more portable.
2399+ Process process = Runtime .getRuntime ().exec (new String []{"stat" ,
2400+ "-f" ,
2401+ "%u" ,
2402+ file .getAbsolutePath ()});
2403+ int attempts = this .attempts ;
2404+ boolean exited = false ;
2405+ String line = new BufferedReader (new InputStreamReader (process .getInputStream (), "UTF-8" )).readLine ();
2406+ do {
2407+ try {
2408+ if (process .exitValue () != 0 ) {
2409+ throw new IllegalStateException ("Error while executing stat" );
2410+ }
2411+ exited = true ;
2412+ break ;
2413+ } catch (IllegalThreadStateException ignored ) {
2414+ try {
2415+ Thread .sleep (timeUnit .toMillis (pause ));
2416+ } catch (InterruptedException exception ) {
2417+ Thread .currentThread ().interrupt ();
2418+ throw new IllegalStateException (exception );
2419+ }
2420+ }
2421+ } while (--attempts > 0 );
2422+ if (!exited ) {
2423+ process .destroy ();
2424+ throw new IllegalStateException ("Command for stat did not exit in time" );
2425+ }
2426+ return Integer .parseInt (line );
2427+ } catch (IOException exception ) {
2428+ throw new IllegalStateException ("Unable to execute stat command" , exception );
2429+ }
2430+ }
2431+ }
2432+
2433+ class ForAixEnvironment implements PosixOwner {
2434+
2435+ /**
2436+ * The maximum amount of attempts for checking the result of a foreign process.
2437+ */
2438+ private final int attempts ;
2439+
2440+ /**
2441+ * The pause between two checks for another process to return.
2442+ */
2443+ private final long pause ;
2444+
2445+ /**
2446+ * The time unit of the pause time.
2447+ */
2448+ private final TimeUnit timeUnit ;
2449+
2450+ /**
2451+ * Creates a new connector for an AIX POSIX enviornment using stat.
2452+ *
2453+ * @param attempts The maximum amount of attempts for checking the result of a foreign process.
2454+ * @param pause The pause between two checks for another process to return.
2455+ * @param timeUnit The time unit of the pause time.
2456+ */
2457+ public ForAixEnvironment (int attempts , long pause , TimeUnit timeUnit ) {
2458+ this .attempts = attempts ;
2459+ this .pause = pause ;
2460+ this .timeUnit = timeUnit ;
2461+ }
2462+
2463+ private static final Pattern AIX_OWNER_PATTERN = Pattern .compile ("Owner: (\\ d+)\\ (" );
2464+
2465+ /**
2466+ * Returns the user id of the owner of the supplied file.
2467+ *
2468+ * @param file The file for which to locate the owner.
2469+ * @return The owner id of the supplied file.
2470+ */
2471+ @ Override
2472+ public int getOwnerIdOf (File file ) {
2473+ try {
2474+ Process process = Runtime .getRuntime ().exec (new String []{"istat" , file .getAbsolutePath ()});
2475+ int attempts = this .attempts ;
2476+ boolean exited = false ;
2477+ BufferedReader bufferedReader = new BufferedReader (new InputStreamReader (process .getInputStream (), "UTF-8" ));
2478+ StringBuilder output = new StringBuilder ();
2479+ String line ;
2480+ while ((line = bufferedReader .readLine ()) != null ) {
2481+ output .append (line ).append ("\n " );
2482+ }
2483+ do {
2484+ try {
2485+ if (process .exitValue () != 0 ) {
2486+ throw new IllegalStateException ("Error while executing istat" );
2487+ }
2488+ exited = true ;
2489+ break ;
2490+ } catch (IllegalThreadStateException ignored ) {
2491+ try {
2492+ Thread .sleep (timeUnit .toMillis (pause ));
2493+ } catch (InterruptedException exception ) {
2494+ Thread .currentThread ().interrupt ();
2495+ throw new IllegalStateException (exception );
2496+ }
2497+ }
2498+ } while (--attempts > 0 );
2499+ if (!exited ) {
2500+ process .destroy ();
2501+ throw new IllegalStateException ("Command for istat did not exit in time" );
2502+ }
2503+ Matcher matcher = AIX_OWNER_PATTERN .matcher (output .toString ());
2504+ // Find and print the Owner UID
2505+ if (matcher .find ()) {
2506+ return Integer .parseInt (matcher .group (1 ));
2507+ } else {
2508+ throw new IllegalStateException ("Unable to parse response from istat command: " + output );
2509+ }
2510+ } catch (IOException exception ) {
2511+ throw new IllegalStateException ("Unable to execute istat command" , exception );
2512+ }
2513+ }
2514+ }
2515+
2516+ class ForMacEnvironment implements PosixOwner {
2517+
2518+ /**
2519+ * The maximum amount of attempts for checking the result of a foreign process.
2520+ */
2521+ private final int attempts ;
2522+
2523+ /**
2524+ * The pause between two checks for another process to return.
2525+ */
2526+ private final long pause ;
2527+
2528+ /**
2529+ * The time unit of the pause time.
2530+ */
2531+ private final TimeUnit timeUnit ;
2532+
2533+ /**
2534+ * Creates a new connector for a Mac POSIX enviornment using stat.
2535+ *
2536+ * @param attempts The maximum amount of attempts for checking the result of a foreign process.
2537+ * @param pause The pause between two checks for another process to return.
2538+ * @param timeUnit The time unit of the pause time.
2539+ */
2540+ public ForMacEnvironment (int attempts , long pause , TimeUnit timeUnit ) {
2541+ this .attempts = attempts ;
2542+ this .pause = pause ;
2543+ this .timeUnit = timeUnit ;
2544+ }
2545+
2546+ /**
2547+ * Returns the user id of the owner of the supplied file.
2548+ *
2549+ * @param file The file for which to locate the owner.
2550+ * @return The owner id of the supplied file.
2551+ */
2552+ @ Override
2553+ public int getOwnerIdOf (File file ) {
2554+ try {
2555+ // The binding for 'stat' is very platform dependant. To avoid the complexity of binding the correct method,
2556+ // stat is called as a separate command. This is less efficient but more portable.
2557+ Process process = Runtime .getRuntime ().exec (new String []{"stat" ,
2558+ "-f" ,
2559+ "%u" ,
2560+ file .getAbsolutePath ()});
2561+ int attempts = this .attempts ;
2562+ boolean exited = false ;
2563+ String line = new BufferedReader (new InputStreamReader (process .getInputStream (), "UTF-8" )).readLine ();
2564+ do {
2565+ try {
2566+ if (process .exitValue () != 0 ) {
2567+ throw new IllegalStateException ("Error while executing stat" );
2568+ }
2569+ exited = true ;
2570+ break ;
2571+ } catch (IllegalThreadStateException ignored ) {
2572+ try {
2573+ Thread .sleep (timeUnit .toMillis (pause ));
2574+ } catch (InterruptedException exception ) {
2575+ Thread .currentThread ().interrupt ();
2576+ throw new IllegalStateException (exception );
2577+ }
2578+ }
2579+ } while (--attempts > 0 );
2580+ if (!exited ) {
2581+ process .destroy ();
2582+ throw new IllegalStateException ("Command for stat did not exit in time" );
2583+ }
2584+ return Integer .parseInt (line );
2585+ } catch (IOException exception ) {
2586+ throw new IllegalStateException ("Unable to execute stat command" , exception );
2587+ }
2588+ }
2589+ }
2590+ }
23882591 }
23892592
23902593 /**
0 commit comments