Skip to content

Commit 601f05e

Browse files
author
Alexander Matveev
committed
8352480: Don't follow symlinks in additional content for app images
Reviewed-by: asemenyuk
1 parent 2661f62 commit 601f05e

File tree

3 files changed

+72
-39
lines changed

3 files changed

+72
-39
lines changed

src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
2828
import java.io.IOException;
2929
import java.io.InputStream;
3030
import java.nio.file.Files;
31+
import java.nio.file.LinkOption;
3132
import java.nio.file.Path;
3233
import java.util.ArrayList;
3334
import java.util.Map;
@@ -107,7 +108,8 @@ protected void copyApplication(Map<String, ? super Object> params)
107108
List<String> items = APP_CONTENT.fetchFrom(params);
108109
for (String item : items) {
109110
FileUtils.copyRecursive(Path.of(item),
110-
appLayout.contentDirectory().resolve(Path.of(item).getFileName()));
111+
appLayout.contentDirectory().resolve(Path.of(item).getFileName()),
112+
LinkOption.NOFOLLOW_LINKS);
111113
}
112114
}
113115

test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ static PackageHandlers createDmgPackageHandlers() {
178178
private static int installDmg(JPackageCommand cmd) {
179179
cmd.verifyIsOfType(PackageType.MAC_DMG);
180180
withExplodedDmg(cmd, dmgImage -> {
181-
Executor.of("sudo", "cp", "-r")
181+
Executor.of("sudo", "cp", "-R")
182182
.addArgument(dmgImage)
183183
.addArgument(getInstallationDirectory(cmd).getParent())
184184
.execute(0);
@@ -205,7 +205,7 @@ private static Path unpackDmg(JPackageCommand cmd, Path destinationDir) {
205205
}
206206

207207
withExplodedDmg(cmd, dmgImage -> {
208-
Executor.of("cp", "-r")
208+
Executor.of("cp", "-R")
209209
.addArgument(dmgImage)
210210
.addArgument(unpackDir)
211211
.execute();

test/jdk/tools/jpackage/share/AppContentTest.java

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,20 @@
2121
* questions.
2222
*/
2323

24+
import static jdk.internal.util.OperatingSystem.LINUX;
25+
import static jdk.internal.util.OperatingSystem.MACOS;
26+
import static java.util.stream.Collectors.joining;
27+
2428
import java.io.IOException;
2529
import java.nio.file.Files;
2630
import java.nio.file.Path;
2731
import jdk.jpackage.test.PackageTest;
2832
import jdk.jpackage.test.TKit;
2933
import jdk.jpackage.test.Annotations.Test;
30-
import jdk.jpackage.test.Annotations.Parameters;
34+
import jdk.jpackage.test.Annotations.Parameter;
3135
import java.util.Arrays;
3236
import java.util.Collection;
3337
import java.util.List;
34-
import static java.util.stream.Collectors.joining;
3538
import java.util.stream.Stream;
3639
import jdk.jpackage.internal.util.FileUtils;
3740
import jdk.jpackage.internal.util.function.ThrowingFunction;
@@ -56,6 +59,7 @@ public class AppContentTest {
5659

5760
private static final String TEST_JAVA = "apps/PrintEnv.java";
5861
private static final String TEST_DUKE = "apps/dukeplug.png";
62+
private static final String TEST_DUKE_LINK = "dukeplugLink.txt";
5963
private static final String TEST_DIR = "apps";
6064
private static final String TEST_BAD = "non-existant";
6165

@@ -67,24 +71,20 @@ public class AppContentTest {
6771
// Need to prepare arguments for `--app-content` accordingly.
6872
private static final boolean copyInResources = TKit.isOSX();
6973

70-
private final List<String> testPathArgs;
71-
72-
@Parameters
73-
public static Collection<?> data() {
74-
return List.of(new String[][]{
75-
{TEST_JAVA, TEST_DUKE}, // include two files in two options
76-
{TEST_JAVA, TEST_BAD}, // try to include non-existant content
77-
{TEST_JAVA + "," + TEST_DUKE, TEST_DIR}, // two files in one option,
78-
// and a dir tree in another option.
79-
});
80-
}
81-
82-
public AppContentTest(String... testPathArgs) {
83-
this.testPathArgs = List.of(testPathArgs);
84-
}
74+
private static final String RESOURCES_DIR = "Resources";
75+
private static final String LINKS_DIR = "Links";
8576

8677
@Test
87-
public void test() throws Exception {
78+
// include two files in two options
79+
@Parameter({TEST_JAVA, TEST_DUKE})
80+
// try to include non-existant content
81+
@Parameter({TEST_JAVA, TEST_BAD})
82+
// two files in one option and a dir tree in another option.
83+
@Parameter({TEST_JAVA + "," + TEST_DUKE, TEST_DIR})
84+
// include one file and one link to the file
85+
@Parameter(value = {TEST_JAVA, TEST_DUKE_LINK}, ifOS = {MACOS,LINUX})
86+
public void test(String... args) throws Exception {
87+
final List<String> testPathArgs = List.of(args);
8888
final int expectedJPackageExitCode;
8989
if (testPathArgs.contains(TEST_BAD)) {
9090
expectedJPackageExitCode = 1;
@@ -98,15 +98,19 @@ public void test() throws Exception {
9898
.addRunOnceInitializer(appContentInitializer::initAppContent)
9999
.addInitializer(appContentInitializer::applyTo)
100100
.addInstallVerifier(cmd -> {
101-
Path baseDir = getAppContentRoot(cmd);
102101
for (String arg : testPathArgs) {
103102
List<String> paths = Arrays.asList(arg.split(","));
104103
for (String p : paths) {
105104
Path name = Path.of(p).getFileName();
106-
TKit.assertPathExists(baseDir.resolve(name), true);
105+
if (isSymlinkPath(name)) {
106+
TKit.assertSymbolicLinkExists(getAppContentRoot(cmd)
107+
.resolve(LINKS_DIR).resolve(name));
108+
} else {
109+
TKit.assertPathExists(getAppContentRoot(cmd)
110+
.resolve(name), true);
111+
}
107112
}
108113
}
109-
110114
})
111115
.setExpectedExitCode(expectedJPackageExitCode)
112116
.run();
@@ -115,12 +119,16 @@ public void test() throws Exception {
115119
private static Path getAppContentRoot(JPackageCommand cmd) {
116120
Path contentDir = cmd.appLayout().contentDirectory();
117121
if (copyInResources) {
118-
return contentDir.resolve("Resources");
122+
return contentDir.resolve(RESOURCES_DIR);
119123
} else {
120124
return contentDir;
121125
}
122126
}
123127

128+
private static boolean isSymlinkPath(Path v) {
129+
return v.getFileName().toString().contains("Link");
130+
}
131+
124132
private static final class AppContentInitializer {
125133
AppContentInitializer(List<String> appContentArgs) {
126134
appContentPathGroups = appContentArgs.stream().map(arg -> {
@@ -144,28 +152,51 @@ void applyTo(JPackageCommand cmd) {
144152
}
145153

146154
private static Path copyAppContentPath(Path appContentPath) throws IOException {
147-
var appContentArg = TKit.createTempDirectory("app-content").resolve("Resources");
155+
var appContentArg = TKit.createTempDirectory("app-content").resolve(RESOURCES_DIR);
148156
var srcPath = TKit.TEST_SRC_ROOT.resolve(appContentPath);
149157
var dstPath = appContentArg.resolve(srcPath.getFileName());
150158
Files.createDirectories(dstPath.getParent());
151159
FileUtils.copyRecursive(srcPath, dstPath);
152160
return appContentArg;
153161
}
154162

155-
private static List<Path> initAppContentPaths(List<Path> appContentPaths) {
163+
private static Path createAppContentLink(Path appContentPath) throws IOException {
164+
var appContentArg = TKit.createTempDirectory("app-content");
156165
if (copyInResources) {
157-
return appContentPaths.stream().map(appContentPath -> {
158-
if (appContentPath.endsWith(TEST_BAD)) {
159-
return appContentPath;
160-
} else {
161-
return ThrowingFunction.toFunction(
162-
AppContentInitializer::copyAppContentPath).apply(
163-
appContentPath);
164-
}
165-
}).toList();
166-
} else {
167-
return appContentPaths.stream().map(TKit.TEST_SRC_ROOT::resolve).toList();
166+
appContentArg = appContentArg.resolve(RESOURCES_DIR).resolve(LINKS_DIR);
167+
} else {
168+
appContentArg = appContentArg.resolve(LINKS_DIR);
168169
}
170+
171+
var dstPath = appContentArg.resolve(appContentPath.getFileName());
172+
Files.createDirectories(dstPath.getParent());
173+
174+
// Create target file for a link
175+
String tagetName = dstPath.getFileName().toString().replace("Link", "");
176+
Path targetPath = dstPath.getParent().resolve(tagetName);
177+
Files.write(targetPath, "foo".getBytes());
178+
// Create link
179+
Files.createSymbolicLink(dstPath, targetPath.getFileName());
180+
181+
return appContentArg;
182+
}
183+
184+
private static List<Path> initAppContentPaths(List<Path> appContentPaths) {
185+
return appContentPaths.stream().map(appContentPath -> {
186+
if (appContentPath.endsWith(TEST_BAD)) {
187+
return appContentPath;
188+
} else if (isSymlinkPath(appContentPath)) {
189+
return ThrowingFunction.toFunction(
190+
AppContentInitializer::createAppContentLink).apply(
191+
appContentPath);
192+
} else if (copyInResources) {
193+
return ThrowingFunction.toFunction(
194+
AppContentInitializer::copyAppContentPath).apply(
195+
appContentPath);
196+
} else {
197+
return TKit.TEST_SRC_ROOT.resolve(appContentPath);
198+
}
199+
}).toList();
169200
}
170201

171202
private List<String> jpackageArgs;

0 commit comments

Comments
 (0)