|
16 | 16 |
|
17 | 17 | import static com.google.common.base.StandardSystemProperty.JAVA_IO_TMPDIR;
|
18 | 18 | import static com.google.common.base.StandardSystemProperty.USER_NAME;
|
| 19 | +import static com.google.common.base.Throwables.throwIfUnchecked; |
19 | 20 | import static java.nio.file.attribute.AclEntryFlag.DIRECTORY_INHERIT;
|
20 | 21 | import static java.nio.file.attribute.AclEntryFlag.FILE_INHERIT;
|
21 | 22 | import static java.nio.file.attribute.AclEntryType.ALLOW;
|
22 | 23 | import static java.nio.file.attribute.PosixFilePermissions.asFileAttribute;
|
| 24 | +import static java.util.Objects.requireNonNull; |
23 | 25 |
|
24 | 26 | import com.google.common.annotations.GwtIncompatible;
|
25 | 27 | import com.google.common.annotations.J2ktIncompatible;
|
| 28 | +import com.google.common.annotations.VisibleForTesting; |
26 | 29 | import com.google.common.collect.ImmutableList;
|
27 | 30 | import com.google.j2objc.annotations.J2ObjCIncompatible;
|
28 | 31 | import java.io.File;
|
29 | 32 | import java.io.IOException;
|
| 33 | +import java.lang.reflect.InvocationTargetException; |
| 34 | +import java.lang.reflect.Method; |
30 | 35 | import java.nio.file.FileSystems;
|
31 | 36 | import java.nio.file.Paths;
|
32 | 37 | import java.nio.file.attribute.AclEntry;
|
@@ -98,6 +103,20 @@ private static TempFileCreator pickSecureCreator() {
|
98 | 103 | return new JavaIoCreator();
|
99 | 104 | }
|
100 | 105 |
|
| 106 | + /** |
| 107 | + * Creates the permissions normally used for Windows filesystems, looking up the user afresh, even |
| 108 | + * if previous calls have initialized the {@code PermissionSupplier} fields. |
| 109 | + * |
| 110 | + * <p>This lets us test the effects of different values of the {@code user.name} system property |
| 111 | + * without needing a separate VM or classloader. |
| 112 | + */ |
| 113 | + @IgnoreJRERequirement // used only when Path is available (and only from tests) |
| 114 | + @VisibleForTesting |
| 115 | + static void testMakingUserPermissionsFromScratch() throws IOException { |
| 116 | + // All we're testing is whether it throws. |
| 117 | + FileAttribute<?> unused = JavaNioCreator.userPermissions().get(); |
| 118 | + } |
| 119 | + |
101 | 120 | @IgnoreJRERequirement // used only when Path is available
|
102 | 121 | private static final class JavaNioCreator extends TempFileCreator {
|
103 | 122 | @Override
|
@@ -150,7 +169,7 @@ private static PermissionSupplier userPermissions() {
|
150 | 169 | UserPrincipal user =
|
151 | 170 | FileSystems.getDefault()
|
152 | 171 | .getUserPrincipalLookupService()
|
153 |
| - .lookupPrincipalByName(USER_NAME.value()); |
| 172 | + .lookupPrincipalByName(getUsername()); |
154 | 173 | ImmutableList<AclEntry> acl =
|
155 | 174 | ImmutableList.of(
|
156 | 175 | AclEntry.newBuilder()
|
@@ -179,6 +198,62 @@ public ImmutableList<AclEntry> value() {
|
179 | 198 | };
|
180 | 199 | }
|
181 | 200 | }
|
| 201 | + |
| 202 | + private static String getUsername() { |
| 203 | + /* |
| 204 | + * https://github.com/google/guava/issues/6634: ProcessHandle has more accurate information, |
| 205 | + * but that class isn't available under all environments that we support. We use it if |
| 206 | + * available and fall back if not. |
| 207 | + */ |
| 208 | + String fromSystemProperty = requireNonNull(USER_NAME.value()); |
| 209 | + |
| 210 | + try { |
| 211 | + Class<?> processHandleClass = Class.forName("java.lang.ProcessHandle"); |
| 212 | + Class<?> processHandleInfoClass = Class.forName("java.lang.ProcessHandle$Info"); |
| 213 | + Class<?> optionalClass = Class.forName("java.util.Optional"); |
| 214 | + /* |
| 215 | + * We don't *need* to use reflection to access Optional: It's available on all JDKs we |
| 216 | + * support, and Android code won't get this far, anyway, because ProcessHandle is |
| 217 | + * unavailable. But given how much other reflection we're using, we might as well use it |
| 218 | + * here, too, so that we don't need to also suppress an AndroidApiChecker error. |
| 219 | + */ |
| 220 | + |
| 221 | + Method currentMethod = processHandleClass.getMethod("current"); |
| 222 | + Method infoMethod = processHandleClass.getMethod("info"); |
| 223 | + Method userMethod = processHandleInfoClass.getMethod("user"); |
| 224 | + Method orElseMethod = optionalClass.getMethod("orElse", Object.class); |
| 225 | + |
| 226 | + Object current = currentMethod.invoke(null); |
| 227 | + Object info = infoMethod.invoke(current); |
| 228 | + Object user = userMethod.invoke(info); |
| 229 | + return (String) requireNonNull(orElseMethod.invoke(user, fromSystemProperty)); |
| 230 | + } catch (ClassNotFoundException runningUnderAndroidOrJava8) { |
| 231 | + /* |
| 232 | + * I'm not sure that we could actually get here for *Android*: I would expect us to enter |
| 233 | + * the POSIX code path instead. And if we tried this code path, we'd have trouble unless we |
| 234 | + * were running under a new enough version of Android to support NIO. |
| 235 | + * |
| 236 | + * So this is probably just the "Windows Java 8" case. In that case, if we wanted *another* |
| 237 | + * layer of fallback before consulting the system property, we could try |
| 238 | + * com.sun.security.auth.module.NTSystem. |
| 239 | + * |
| 240 | + * But for now, we use the value from the system property as our best guess. |
| 241 | + */ |
| 242 | + return fromSystemProperty; |
| 243 | + } catch (InvocationTargetException e) { |
| 244 | + throwIfUnchecked(e.getCause()); // in case it's an Error or something |
| 245 | + return fromSystemProperty; // should be impossible |
| 246 | + } catch (NoSuchMethodException shouldBeImpossible) { |
| 247 | + return fromSystemProperty; |
| 248 | + } catch (IllegalAccessException shouldBeImpossible) { |
| 249 | + /* |
| 250 | + * We don't merge these into `catch (ReflectiveOperationException ...)` or an equivalent |
| 251 | + * multicatch because ReflectiveOperationException isn't available under Android: |
| 252 | + * b/124188803 |
| 253 | + */ |
| 254 | + return fromSystemProperty; |
| 255 | + } |
| 256 | + } |
182 | 257 | }
|
183 | 258 |
|
184 | 259 | private static final class JavaIoCreator extends TempFileCreator {
|
|
0 commit comments