This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 237882
Collapse All | Expand All

(-)a/masterfs/manifest.mf (-1 / +1 lines)
Lines 1-7 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.modules.masterfs/2
2
OpenIDE-Module: org.netbeans.modules.masterfs/2
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/masterfs/resources/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/masterfs/resources/Bundle.properties
4
OpenIDE-Module-Specification-Version: 2.45
4
OpenIDE-Module-Specification-Version: 2.46
5
OpenIDE-Module-Recommends: org.netbeans.modules.masterfs.providers.Notifier
5
OpenIDE-Module-Recommends: org.netbeans.modules.masterfs.providers.Notifier
6
OpenIDE-Module-Provides: org.openide.filesystems.FileUtil.toFileObject
6
OpenIDE-Module-Provides: org.openide.filesystems.FileUtil.toFileObject
7
AutoUpdate-Show-In-Client: false
7
AutoUpdate-Show-In-Client: false
(-)a/masterfs/nbproject/project.xml (-1 / +1 lines)
Lines 63-69 Link Here
63
                    <build-prerequisite/>
63
                    <build-prerequisite/>
64
                    <compile-dependency/>
64
                    <compile-dependency/>
65
                    <run-dependency>
65
                    <run-dependency>
66
                        <specification-version>8.0</specification-version>
66
                        <specification-version>8.10</specification-version>
67
                    </run-dependency>
67
                    </run-dependency>
68
                </dependency>
68
                </dependency>
69
                <dependency>
69
                <dependency>
(-)a/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/BaseFileObj.java (+86 lines)
Lines 59-64 Link Here
59
59
60
import javax.swing.event.EventListenerList;
60
import javax.swing.event.EventListenerList;
61
import java.io.*;
61
import java.io.*;
62
import java.nio.file.FileSystems;
63
import java.nio.file.Files;
64
import java.nio.file.Path;
65
import java.security.AccessController;
66
import java.security.PrivilegedActionException;
67
import java.security.PrivilegedExceptionAction;
62
import java.util.ArrayDeque;
68
import java.util.ArrayDeque;
63
import java.util.Arrays;
69
import java.util.Arrays;
64
import java.util.Date;
70
import java.util.Date;
Lines 1061-1066 Link Here
1061
    FolderObj getExistingParent() {         
1067
    FolderObj getExistingParent() {         
1062
        return getExistingParentFor(getFileName().getFile(), getFactory());
1068
        return getExistingParentFor(getFileName().getFile(), getFactory());
1063
    }
1069
    }
1070
1071
    /**
1072
     * Get {@link Path} object for this BaseFileObj.
1073
     */
1074
    private Path getNativePath() throws IOException {
1075
        File file = getFileName().getFile();
1076
        final Path path;
1077
        try {
1078
            path = file.toPath();
1079
        } catch (RuntimeException e) {
1080
            throw new IOException("Cannot get Path for " + this, e);    //NOI18N
1081
        }
1082
        return path;
1083
    }
1084
1085
    @Override
1086
    public boolean isSymbolicLink() throws IOException {
1087
        Path p = getNativePath();
1088
        return Files.isSymbolicLink(p);
1089
    }
1090
1091
    @Override
1092
    public FileObject readSymbolicLink() throws IOException {
1093
        final Path path = getNativePath();
1094
        try {
1095
            return AccessController.doPrivileged(
1096
                    new PrivilegedExceptionAction<FileObject>() {
1097
1098
                        @Override
1099
                        public FileObject run() throws Exception {
1100
                            Path target = Files.readSymbolicLink(path);
1101
                            Path absoluteTarget = target.isAbsolute()
1102
                                ? target
1103
                                : path.getParent().resolve(target);
1104
                            File file = absoluteTarget.toFile();
1105
                            File normFile = FileUtil.normalizeFile(file);
1106
                            return FileBasedFileSystem.getFileObject(normFile);
1107
                        }
1108
                    });
1109
        } catch (PrivilegedActionException ex) {
1110
            throw new IOException(ex);
1111
        }
1112
    }
1113
1114
    @Override
1115
    public String readSymbolicLinkPath() throws IOException {
1116
        final Path path = getNativePath();
1117
        try {
1118
            return AccessController.doPrivileged(
1119
                    new PrivilegedExceptionAction<String>() {
1120
1121
                        @Override
1122
                        public String run() throws Exception {
1123
                            Path target = Files.readSymbolicLink(path);
1124
                            return target.toString();
1125
                        }
1126
                    });
1127
        } catch (PrivilegedActionException ex) {
1128
            throw new IOException(ex);
1129
        }
1130
    }
1131
1132
    @Override
1133
    public FileObject getRealFileObject() throws IOException {
1134
        final Path path = getNativePath();
1135
        try {
1136
            return AccessController.doPrivileged(
1137
                    new PrivilegedExceptionAction<FileObject>() {
1138
1139
                        @Override
1140
                        public FileObject run() throws Exception {
1141
                            Path realPath = path.toRealPath();
1142
                            File realFile = realPath.toFile();
1143
                            return FileBasedFileSystem.getFileObject(realFile);
1144
                        }
1145
                    });
1146
        } catch (PrivilegedActionException ex) {
1147
            throw new IOException(ex);
1148
        }
1149
    }
1064
    
1150
    
1065
    private static class FileEventImpl extends FileEvent implements Enumeration<FileEvent> {
1151
    private static class FileEventImpl extends FileEvent implements Enumeration<FileEvent> {
1066
        static {
1152
        static {
(-)a/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FileObjSymlinkTest.java (+285 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2013 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.modules.masterfs.filebasedfs.fileobjects;
43
44
import java.io.File;
45
import java.io.IOException;
46
import java.nio.file.Files;
47
import java.nio.file.Path;
48
import java.nio.file.Paths;
49
import org.netbeans.junit.NbTestCase;
50
import org.openide.filesystems.FileObject;
51
import org.openide.filesystems.FileUtil;
52
53
/**
54
 * Test support for detection and reading of symbolic links.
55
 *
56
 * @author jhavlin
57
 */
58
public class FileObjSymlinkTest extends NbTestCase {
59
60
    public FileObjSymlinkTest(String name) {
61
        super(name);
62
    }
63
64
    @Override
65
    protected void setUp() throws Exception {
66
        deleteSymlinks(getWorkDir());
67
        clearWorkDir();
68
    }
69
70
    public void testIsSymbolicLink() throws IOException {
71
        if (!checkSymlinksSupported()) {
72
            return;
73
        }
74
        File dir = getWorkDir();
75
        Path p = dir.toPath();
76
        Path data = p.resolve("data.dat");
77
        Path link = p.resolve("link.lk");
78
        data.toFile().createNewFile();
79
        Files.createSymbolicLink(link, data);
80
        FileObject dirFO = FileUtil.toFileObject(dir);
81
        dirFO.refresh();
82
        FileObject dataFO = dirFO.getFileObject("data.dat");
83
        FileObject linkFO = dirFO.getFileObject("link.lk");
84
        assertFalse(dataFO.isSymbolicLink());
85
        assertTrue(linkFO.isSymbolicLink());
86
    }
87
88
    /**
89
     * Test isRecursiveSymbolicLink method. Use this folder tree:
90
     * <pre>
91
     * - workdir
92
     *   - a
93
     *     - b
94
     *       - c (symlink to a)
95
     *       - d (symlink to e)
96
     *   - e
97
     * </pre>
98
     *
99
     * @throws java.io.IOException
100
     */
101
    public void testIsRecursiveSymbolicLink() throws IOException {
102
        if (!checkSymlinksSupported()) {
103
            return;
104
        }
105
        File dir = getWorkDir();
106
        File a = new File(dir, "a");
107
        File b = new File(a, "b");
108
        File c = new File(b, "c");
109
        File d = new File(b, "d");
110
        File e = new File(dir, "e");
111
        b.mkdirs();
112
        e.mkdirs();
113
        Files.createSymbolicLink(c.toPath(), a.toPath());
114
        Files.createSymbolicLink(d.toPath(), e.toPath());
115
        FileObject dirFO = FileUtil.toFileObject(dir);
116
        dirFO.refresh();
117
        FileObject cFO = dirFO.getFileObject("a/b/c");
118
        FileObject dFO = dirFO.getFileObject("a/b/d");
119
        assertTrue(cFO.isRecursiveSymbolicLink());
120
        assertFalse(dFO.isRecursiveSymbolicLink());
121
        assertFalse(dirFO.isRecursiveSymbolicLink());
122
    }
123
124
    /**
125
     * Test isRecursiveSymbolicLink method. Use this folder tree:
126
     * <pre>
127
     * - workdir
128
     *   - a
129
     *     - b
130
     *       - c (symlink to d)
131
     *   - d (symlink to a)
132
     * </pre>
133
     *
134
     * @throws java.io.IOException
135
     */
136
    public void testIsRecursiveSymbolicLinkIndirect() throws IOException {
137
        if (!checkSymlinksSupported()) {
138
            return;
139
        }
140
        File dir = getWorkDir();
141
        File a = new File(dir, "a");
142
        File b = new File(a, "b");
143
        File c = new File(b, "c");
144
        File d = new File(dir, "d");
145
        b.mkdirs();
146
        Files.createSymbolicLink(d.toPath(), a.toPath());
147
        Files.createSymbolicLink(c.toPath(), d.toPath());
148
        FileObject dirFO = FileUtil.toFileObject(dir);
149
        FileObject cFO = dirFO.getFileObject("a/b/c");
150
        assertTrue(cFO.isRecursiveSymbolicLink());
151
    }
152
153
    public void testReadSymbolicLinkAbsolute() throws IOException {
154
        if (!checkSymlinksSupported()) {
155
            return;
156
        }
157
        File dir = getWorkDir();
158
        File data = new File(dir, "data.dat");
159
        File link = new File(dir, "link.lnk");
160
        data.createNewFile();
161
        Files.createSymbolicLink(link.toPath(), data.toPath());
162
        FileObject linkFO = FileUtil.toFileObject(link);
163
        FileObject dataFO = linkFO.readSymbolicLink();
164
        assertNotSame(linkFO, dataFO);
165
        assertNotNull(dataFO);
166
        assertEquals("data.dat", dataFO.getNameExt());
167
    }
168
169
    public void testReadSymbolicLinkRelative() throws IOException {
170
        if (!checkSymlinksSupported()) {
171
            return;
172
        }
173
        File dir = getWorkDir();
174
        File folder = new File(dir, "folder");
175
        File link = new File(dir, "link");
176
        folder.mkdir();
177
        Path lp = Files.createSymbolicLink(link.toPath(), Paths.get("folder"));
178
        assertNotNull(lp);
179
        FileObject linkFO = FileUtil.toFileObject(link);
180
        assertNotNull(linkFO);
181
        FileObject dataFO = linkFO.readSymbolicLink();
182
        assertNotSame(linkFO, dataFO);
183
        assertNotNull(dataFO);
184
        assertEquals("folder", dataFO.getNameExt());
185
    }
186
187
    public void testReadSymbolicLinkPath() throws IOException {
188
        if (!checkSymlinksSupported()) {
189
            return;
190
        }
191
        File dir = getWorkDir();
192
        File data = new File(dir, "data.dat");
193
        File link = new File(dir, "link.lnk");
194
        data.createNewFile();
195
        Files.createSymbolicLink(link.toPath(), data.toPath());
196
        FileObject linkFO = FileUtil.toFileObject(link);
197
        assertTrue(linkFO.readSymbolicLinkPath().endsWith("data.dat"));
198
    }
199
200
    /**
201
     * Test getRealFileObject method.
202
     *
203
     * Use this directory tree:
204
     * <pre>
205
     * - workdir
206
     *   - a
207
     *     - data.dat
208
     *   - b
209
     *     - link.lnk (symlink to data.dat)
210
     *   - c
211
     *     - link2.lnk (symlink to link.link)
212
     *   - d
213
     *     - folderLink (symlink to c)
214
     * </pre>
215
     * @throws java.io.IOException
216
     */
217
    public void testGetRealFileObject() throws IOException {
218
        if (!checkSymlinksSupported()) {
219
            return;
220
        }
221
        File dir = getWorkDir();
222
        File a = new File(dir, "a");
223
        File dataDat = new File(a, "data.dat");
224
        File b = new File(dir, "b");
225
        File linkLnk = new File(b, "link.lnk");
226
        File c = new File(dir, "c");
227
        File link2Lnk = new File(c, "link2.lnk");
228
        File d = new File(dir, "d");
229
        File folderLink = new File(d, "folderLink");
230
        a.mkdir();
231
        dataDat.createNewFile();
232
        b.mkdir();
233
        Files.createSymbolicLink(linkLnk.toPath(), dataDat.toPath());
234
        c.mkdir();
235
        Files.createSymbolicLink(link2Lnk.toPath(), linkLnk.toPath());
236
        d.mkdir();
237
        Files.createSymbolicLink(folderLink.toPath(), c.toPath());
238
        FileObject dirFO = FileUtil.toFileObject(dir);
239
        dirFO.refresh();
240
        FileObject fo = dirFO.getFileObject("d/folderLink/link2.lnk");
241
        assertNotNull(fo);
242
        FileObject realFO = fo.getRealFileObject();
243
        assertNotNull(realFO);
244
        assertTrue(realFO.getPath().endsWith("a/data.dat"));
245
    }
246
247
    /**
248
     * Recursively delete all symlinks in a directory.
249
     */
250
    private void deleteSymlinks(File root) {
251
        for (File f : root.listFiles()) {
252
            if (Files.isSymbolicLink(f.toPath())) {
253
                f.delete();
254
            } else if (f.isDirectory()) {
255
                deleteSymlinks(f);
256
            }
257
        }
258
    }
259
260
    private boolean checkSymlinksSupported() {
261
        File dir;
262
        try {
263
            dir = getWorkDir();
264
        } catch (IOException ex) {
265
            printSkipping();
266
            return false;
267
        }
268
        File a = new File(dir, "a");
269
        try {
270
            File lk = new File(dir, "lk");
271
            Files.createSymbolicLink(lk.toPath(), a.toPath());
272
            lk.delete();
273
            return true;
274
        } catch (RuntimeException e) {
275
        } catch (IOException ex) {
276
        }
277
        printSkipping();
278
        return false;
279
    }
280
281
    private void printSkipping() {
282
        System.out.println(
283
                "Symbolic links are not supported, skipping test " + getName());
284
    }
285
}
(-)a/openide.filesystems/apichanges.xml (+22 lines)
Lines 49-54 Link Here
49
        <apidef name="filesystems">Filesystems API</apidef>
49
        <apidef name="filesystems">Filesystems API</apidef>
50
    </apidefs>
50
    </apidefs>
51
    <changes>
51
    <changes>
52
        <change id="FileObject.symbolicLinks">
53
            <api name="filesystems"/>
54
            <summary>Support detection and reading of symbolic links.</summary>
55
            <version major="8" minor="10"/>
56
            <date year="2013" month="10" day="23"/>
57
            <author login="jhavlin"/>
58
            <compatibility addition="yes"/>
59
            <description>
60
                <p>
61
                    Add methods to FileObject for handling of symbolic links:
62
                </p>
63
                <ul>
64
                    <li><code>isSymbolicLink()</code></li>
65
                    <li><code>isRecursiveSymbolicLink()</code></li>
66
                    <li><code>readSymbolicLink()</code></li>
67
                    <li><code>readSymbolicLinkPath()</code></li>
68
                    <li><code>getRealFileObject()</code></li>
69
                </ul>
70
            </description>
71
            <class package="org.openide.filesystems" name="FileObject"/>
72
            <issue number="237882"/>
73
        </change>
52
        <change id="MultiFileObject.revealEntriesAttribute">
74
        <change id="MultiFileObject.revealEntriesAttribute">
53
            <api name="filesystems"/>
75
            <api name="filesystems"/>
54
            <summary>Allowed to reveal deleted files, or original files overriden by writable layer</summary>
76
            <summary>Allowed to reveal deleted files, or original files overriden by writable layer</summary>
(-)a/openide.filesystems/manifest.mf (-1 / +1 lines)
Lines 2-6 Link Here
2
OpenIDE-Module: org.openide.filesystems
2
OpenIDE-Module: org.openide.filesystems
3
OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties
4
OpenIDE-Module-Layer: org/openide/filesystems/resources/layer.xml
4
OpenIDE-Module-Layer: org/openide/filesystems/resources/layer.xml
5
OpenIDE-Module-Specification-Version: 8.9
5
OpenIDE-Module-Specification-Version: 8.10
6
6
(-)a/openide.filesystems/src/org/openide/filesystems/FileObject.java (-2 / +106 lines)
Lines 65-70 Link Here
65
import java.util.concurrent.Callable;
65
import java.util.concurrent.Callable;
66
import java.util.logging.Level;
66
import java.util.logging.Level;
67
import org.openide.util.Enumerations;
67
import org.openide.util.Enumerations;
68
import org.openide.util.Exceptions;
68
import org.openide.util.NbBundle;
69
import org.openide.util.NbBundle;
69
import org.openide.util.Lookup;
70
import org.openide.util.Lookup;
70
import org.openide.util.Lookup.Result;
71
import org.openide.util.Lookup.Result;
Lines 903-910 Link Here
903
            public FileObject process(FileObject fo, Collection<FileObject> toAdd) {
904
            public FileObject process(FileObject fo, Collection<FileObject> toAdd) {
904
                if (rec && fo.isFolder()) {
905
                if (rec && fo.isFolder()) {
905
                    for (FileObject child : fo.getChildren()) {
906
                    for (FileObject child : fo.getChildren()) {
906
                        if (!FileUtil.isRecursiveSymlink(child)) { // #218795
907
                        try {
907
                            toAdd.add(child);
908
                            if (!child.isRecursiveSymbolicLink()) { // #218795
909
                                toAdd.add(child);
910
                            }
911
                        } catch (IOException ex) {
912
                            ExternalUtil.LOG.log(Level.INFO, null, ex);
908
                        }
913
                        }
909
                    }
914
                    }
910
                }
915
                }
Lines 1254-1259 Link Here
1254
        return false;
1259
        return false;
1255
    }
1260
    }
1256
1261
1262
    /**
1263
     * Check whether this FileObject is a symbolic link.
1264
     *
1265
     * The default implementation returns false, but on filesystems that support
1266
     * symbolic links this method should be overriden.
1267
     *
1268
     * @return True if this FileObject represents a symbolic link, false
1269
     * otherwise.
1270
     * @throws java.io.IOException If some I/O problem occurs.
1271
     * @since openide.filesystem/8.10
1272
     */
1273
    public boolean isSymbolicLink() throws IOException {
1274
        return false;
1275
    }
1276
1277
    /**
1278
     * Check whether this FileObject is a recursive symbolic link.
1279
     *
1280
     * Filesystem implementations can override this method for better
1281
     * performance.
1282
     *
1283
     * @return True if this FileObject represents a symbolic link referring to a
1284
     * directory that is parent of this FileObject, false otherwise.
1285
     * @throws java.io.IOException If some I/O problem occurs.
1286
     * @since openide.filesystem/8.10
1287
     */
1288
    public boolean isRecursiveSymbolicLink() throws IOException {
1289
        if (isSymbolicLink()) {
1290
            FileObject parent = getParent();
1291
            if (parent == null) {
1292
                return false;
1293
            }
1294
            FileObject target = readSymbolicLink();
1295
            if (target != null) {
1296
                FileObject realParent = parent.getRealFileObject();
1297
                FileObject realTarget = target.getRealFileObject();
1298
                return realParent != null && realTarget != null
1299
                        && (realTarget.equals(realParent)
1300
                        || FileUtil.isParentOf(realTarget, realParent));
1301
            } else {
1302
                return false;
1303
            }
1304
        } else {
1305
            return false;
1306
        }
1307
    }
1308
1309
    /**
1310
     * Read symbolic link.
1311
     *
1312
     * If this FileObject represents a symbolic link, return a FileObject it
1313
     * refers to, or null if the referred file or directory does not exist. If
1314
     * this FileObject doesn't represent a symbolic link, the return value is
1315
     * undefined.
1316
     *
1317
     * The default implementation returns null, but on filesystems that support
1318
     * symbolic links this method should be overriden.
1319
     *
1320
     * @return The referred FileObject, or null if it is not available.
1321
     * @throws java.io.IOException If some I/O problem occurs.
1322
     * @since openide.filesystem/8.10
1323
     */
1324
    public FileObject readSymbolicLink() throws IOException {
1325
        return null;
1326
    }
1327
1328
    /**
1329
     * Read symbolic link path.
1330
     *
1331
     * If this FileObject represents a symbolic link, return the path it refers
1332
     * to, which can be absolute or relative. If this FileObject doesn't
1333
     * represent a symbolic link, the return value is undefined.
1334
     *
1335
     * The default implementation returns this FileObject's path, but on
1336
     * filesystems that support symbolic links this method should be overriden.
1337
     *
1338
     * @return The referred FileObject path.
1339
     * @throws java.io.IOException If some I/O problem occurs.
1340
     * @since openide.filesystem/8.10
1341
     */
1342
    public String readSymbolicLinkPath() throws IOException {
1343
        return this.getPath();
1344
    }
1345
1346
    /**
1347
     * Return a FileObject with path where all symbolic links are resolved.
1348
     *
1349
     * The default implementation returns this object, but on filesystems that
1350
     * support symbolic links this method should be overriden.
1351
     *
1352
     * @return The FileObject with path where all symlinks are resolved, or null
1353
     * if it doesn't exist.
1354
     * @throws java.io.IOException If some I/O problem occurs.
1355
     * @since openide.filesystem/8.10
1356
     */
1357
    public FileObject getRealFileObject() throws IOException {
1358
        return this;
1359
    }
1360
1257
    /** Listeners registered from MultiFileObject are considered as priority
1361
    /** Listeners registered from MultiFileObject are considered as priority
1258
     *  listeners.
1362
     *  listeners.
1259
     */
1363
     */
(-)a/openide.filesystems/src/org/openide/filesystems/FileUtil.java (-58 lines)
Lines 58-68 Link Here
58
import java.net.URI;
58
import java.net.URI;
59
import java.net.URL;
59
import java.net.URL;
60
import java.net.URLStreamHandler;
60
import java.net.URLStreamHandler;
61
import java.nio.file.Files;
62
import java.nio.file.Path;
63
import java.security.AccessController;
64
import java.security.PrivilegedActionException;
65
import java.security.PrivilegedExceptionAction;
66
import java.util.ArrayList;
61
import java.util.ArrayList;
67
import java.util.Arrays;
62
import java.util.Arrays;
68
import java.util.Collection;
63
import java.util.Collection;
Lines 2332-2388 Link Here
2332
        int index = path.lastIndexOf('.');  //NOI18N
2327
        int index = path.lastIndexOf('.');  //NOI18N
2333
        return (index != -1) && (index > path.lastIndexOf('/') + 1);    //NOI18N
2328
        return (index != -1) && (index > path.lastIndexOf('/') + 1);    //NOI18N
2334
    }
2329
    }
2335
2336
    /**
2337
     * Check whether this file is a symbolic link that targets to a folder
2338
     * higher in the path. Such link, in case of recursive folder traversing,
2339
     * would cause infinite recursion. The method should not be called from
2340
     * Event Dispatch Thread.
2341
     *
2342
     * @param fileObject FileObject to check.
2343
     * @return True if the file is a link that could cause infinite recursion,
2344
     * false otherwise.
2345
     */
2346
    static boolean isRecursiveSymlink(FileObject fileObject) {
2347
        File file = (File) fileObject.getAttribute("java.io.File"); // NOI18N
2348
        if (file == null) {
2349
            return false;
2350
        }
2351
        final Path path;
2352
        try {
2353
            path = file.toPath();
2354
        } catch (RuntimeException e) {
2355
            LOG.log(Level.INFO, "Cannot get path for {0}", file);       //NOI18N
2356
            LOG.log(Level.FINE, null, e);
2357
            return false;
2358
        }
2359
        if (Files.isSymbolicLink(path)) {
2360
            try {
2361
                return AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
2362
                    @Override
2363
                    public Boolean run () throws IOException {
2364
                        Path target = Files.readSymbolicLink(path);
2365
                        if (!target.isAbsolute()) {
2366
                            target = path.resolve(target);
2367
                        }
2368
                        target = target.toRealPath();
2369
                        for (Path ancestor = path.getParent();
2370
                                ancestor != null; ancestor = ancestor.getParent()) {
2371
                            if (target.equals(ancestor)) {
2372
                                return true;
2373
                            }
2374
                        }
2375
                        return false;
2376
                    }
2377
                });
2378
            } catch (PrivilegedActionException ex) {
2379
                LOG.log(Level.INFO, "Cannot read symbolic link {0}",//NOI18N
2380
                        path);
2381
                LOG.log(Level.FINE, null, ex.getException());
2382
            } catch (SecurityException ex) {
2383
                LOG.log(Level.INFO, null, ex);
2384
            }
2385
        }
2386
        return false;
2387
    }
2388
}
2330
}

Return to bug 237882