Skip to content

Commit 65f6567

Browse files
authored
HADOOP-19488 fix the temporary direction creation on Windows (#7511)
* The Windows filesystem does not recognize the POSIX permissions, and it was causing the directory creation failure. * This PR checks if the filesystem does not support POSIX permissions, it switches to using the user-based, ACL-based permissions that work on Windows.
1 parent 3e8f1f6 commit 65f6567

File tree

2 files changed

+81
-10
lines changed

2 files changed

+81
-10
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/RunJar.java

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,17 @@
2727
import java.net.MalformedURLException;
2828
import java.net.URL;
2929
import java.net.URLClassLoader;
30+
import java.nio.file.FileSystems;
3031
import java.nio.file.Files;
32+
import java.nio.file.attribute.AclEntry;
33+
import java.nio.file.attribute.AclEntryPermission;
3134
import java.nio.file.attribute.FileAttribute;
32-
import java.nio.file.attribute.PosixFilePermission;
3335
import java.nio.file.attribute.PosixFilePermissions;
36+
import java.nio.file.attribute.UserPrincipal;
3437
import java.util.ArrayList;
3538
import java.util.Arrays;
39+
import java.util.Collections;
40+
import java.util.EnumSet;
3641
import java.util.Enumeration;
3742
import java.util.List;
3843
import java.util.Set;
@@ -51,6 +56,10 @@
5156
import org.slf4j.Logger;
5257
import org.slf4j.LoggerFactory;
5358

59+
import static java.nio.file.attribute.AclEntryFlag.DIRECTORY_INHERIT;
60+
import static java.nio.file.attribute.AclEntryFlag.FILE_INHERIT;
61+
import static java.nio.file.attribute.AclEntryType.ALLOW;
62+
5463
/** Run a Hadoop job jar. */
5564
@InterfaceAudience.Private
5665
@InterfaceStability.Unstable
@@ -286,25 +295,19 @@ public void run(String[] args) throws Throwable {
286295
}
287296
mainClassName = mainClassName.replaceAll("/", ".");
288297

289-
File tmpDir = new File(System.getProperty("java.io.tmpdir"));
290-
ensureDirectory(tmpDir);
291-
292298
final File workDir;
293299
try {
294-
FileAttribute<Set<PosixFilePermission>> perms = PosixFilePermissions
295-
.asFileAttribute(PosixFilePermissions.fromString("rwx------"));
296-
workDir = Files.createTempDirectory(tmpDir.toPath(), "hadoop-unjar", perms).toFile();
300+
workDir = createWorkDirectory();
297301
} catch (IOException | SecurityException e) {
298302
// If user has insufficient perms to write to tmpDir, default
299303
// "Permission denied" message doesn't specify a filename.
300304
System.err.println("Error creating temp dir in java.io.tmpdir "
301-
+ tmpDir + " due to " + e.getMessage());
305+
+ System.getProperty("java.io.tmpdir") + " due to "
306+
+ e.getMessage());
302307
System.exit(-1);
303308
return;
304309
}
305310

306-
ensureDirectory(workDir);
307-
308311
ShutdownHookManager.get().addShutdownHook(
309312
new Runnable() {
310313
@Override
@@ -333,6 +336,55 @@ public void run() {
333336
}
334337
}
335338

339+
static File createWorkDirectory() throws IOException {
340+
File tmpDir = new File(System.getProperty("java.io.tmpdir"));
341+
ensureDirectory(tmpDir);
342+
343+
File workDir = Files.createTempDirectory(tmpDir.toPath(), "hadoop-unjar",
344+
directoryPermissions()).toFile();
345+
ensureDirectory(workDir);
346+
return workDir;
347+
}
348+
349+
private static FileAttribute<?> directoryPermissions() throws IOException {
350+
Set<String> views = FileSystems.getDefault().supportedFileAttributeViews();
351+
if (views.contains("posix")) {
352+
return PosixFilePermissions
353+
.asFileAttribute(PosixFilePermissions.fromString("rwx------"));
354+
} else if (views.contains("acl")) {
355+
return userOnly();
356+
} else {
357+
throw new IOException("unrecognized FileSystem type " +
358+
FileSystems.getDefault());
359+
}
360+
}
361+
362+
private static FileAttribute<?> userOnly() throws IOException {
363+
UserPrincipal user =
364+
FileSystems.getDefault()
365+
.getUserPrincipalLookupService()
366+
.lookupPrincipalByName(System.getProperty("user.name"));
367+
List<AclEntry> acl =
368+
Collections.singletonList(AclEntry.newBuilder()
369+
.setType(ALLOW)
370+
.setPrincipal(user)
371+
.setPermissions(EnumSet.allOf(AclEntryPermission.class))
372+
.setFlags(DIRECTORY_INHERIT, FILE_INHERIT)
373+
.build());
374+
return
375+
new FileAttribute<List<AclEntry>>() {
376+
@Override
377+
public String name() {
378+
return "acl:acl";
379+
}
380+
381+
@Override
382+
public List<AclEntry> value() {
383+
return acl;
384+
}
385+
};
386+
}
387+
336388
/**
337389
* Creates a classloader based on the environment that was specified by the
338390
* user. If HADOOP_USE_CLIENT_CLASSLOADER is specified, it creates an

hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestRunJar.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.apache.hadoop.util.RunJar.MATCH_ANY;
2121
import static org.junit.jupiter.api.Assertions.assertEquals;
2222
import static org.junit.jupiter.api.Assertions.assertFalse;
23+
import static org.junit.jupiter.api.Assertions.assertNotNull;
2324
import static org.junit.jupiter.api.Assertions.assertTrue;
2425
import static org.junit.jupiter.api.Assertions.fail;
2526
import static org.mockito.ArgumentMatchers.any;
@@ -197,6 +198,24 @@ private File getUnjarDir(String dirName) {
197198
return unjarDir;
198199
}
199200

201+
/**
202+
* Tests the creation of the temp working directory into which the jars are
203+
* unjarred.
204+
*/
205+
@Test
206+
public void testCreateWorkDirectory() throws Exception {
207+
File workDir = null;
208+
try {
209+
workDir = RunJar.createWorkDirectory();
210+
211+
assertNotNull(workDir, "Work directory should exist and not null");
212+
} finally {
213+
if (workDir != null) {
214+
FileUtil.fullyDelete(workDir);
215+
}
216+
}
217+
}
218+
200219
/**
201220
* Tests the client classloader to verify the main class and its dependent
202221
* class are loaded correctly by the application classloader, and others are

0 commit comments

Comments
 (0)