History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/nio/file/FileTreeWalker.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/nio/file/FileTreeWalker.java+248−0
@@ -0,0 +1,248 @@
1+/*
2+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.nio.file;
27+
28+import java.nio.file.attribute.*;
29+import java.io.IOException;
30+import java.util.*;
31+import sun.nio.fs.BasicFileAttributesHolder;
32+
33+/**
34+ * Simple file tree walker that works in a similar manner to nftw(3C).
35+ *
36+ * @see Files#walkFileTree
37+ */
38+
39+class FileTreeWalker {
40+ private final boolean followLinks;
41+ private final LinkOption[] linkOptions;
42+ private final FileVisitor<? super Path> visitor;
43+ private final int maxDepth;
44+
45+ FileTreeWalker(Set<FileVisitOption> options,
46+ FileVisitor<? super Path> visitor,
47+ int maxDepth)
48+ {
49+ boolean fl = false;
50+ for (FileVisitOption option: options) {
51+ // will throw NPE if options contains null
52+ switch (option) {
53+ case FOLLOW_LINKS : fl = true; break;
54+ default:
55+ throw new AssertionError("Should not get here");
56+ }
57+ }
58+ this.followLinks = fl;
59+ this.linkOptions = (fl) ? new LinkOption[0] :
60+ new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
61+ this.visitor = visitor;
62+ this.maxDepth = maxDepth;
63+ }
64+
65+ /**
66+ * Walk file tree starting at the given file
67+ */
68+ void walk(Path start) throws IOException {
69+ FileVisitResult result = walk(start,
70+ 0,
71+ new ArrayList<AncestorDirectory>());
72+ Objects.requireNonNull(result, "FileVisitor returned null");
73+ }
74+
75+ /**
76+ * @param file
77+ * the directory to visit
78+ * @param depth
79+ * depth remaining
80+ * @param ancestors
81+ * use when cycle detection is enabled
82+ */
83+ private FileVisitResult walk(Path file,
84+ int depth,
85+ List<AncestorDirectory> ancestors)
86+ throws IOException
87+ {
88+ // if attributes are cached then use them if possible
89+ BasicFileAttributes attrs = null;
90+ if ((depth > 0) &&
91+ (file instanceof BasicFileAttributesHolder) &&
92+ (System.getSecurityManager() == null))
93+ {
94+ BasicFileAttributes cached = ((BasicFileAttributesHolder)file).get();
95+ if (!followLinks || !cached.isSymbolicLink())
96+ attrs = cached;
97+ }
98+ IOException exc = null;
99+
100+ // attempt to get attributes of file. If fails and we are following
101+ // links then a link target might not exist so get attributes of link
102+ if (attrs == null) {
103+ try {
104+ try {
105+ attrs = Files.readAttributes(file, BasicFileAttributes.class, linkOptions);
106+ } catch (IOException x1) {
107+ if (followLinks) {
108+ try {
109+ attrs = Files.readAttributes(file,
110+ BasicFileAttributes.class,
111+ LinkOption.NOFOLLOW_LINKS);
112+ } catch (IOException x2) {
113+ exc = x2;
114+ }
115+ } else {
116+ exc = x1;
117+ }
118+ }
119+ } catch (SecurityException x) {
120+ // If access to starting file is denied then SecurityException
121+ // is thrown, otherwise the file is ignored.
122+ if (depth == 0)
123+ throw x;
124+ return FileVisitResult.CONTINUE;
125+ }
126+ }
127+
128+ // unable to get attributes of file
129+ if (exc != null) {
130+ return visitor.visitFileFailed(file, exc);
131+ }
132+
133+ // at maximum depth or file is not a directory
134+ if (depth >= maxDepth || !attrs.isDirectory()) {
135+ return visitor.visitFile(file, attrs);
136+ }
137+
138+ // check for cycles when following links
139+ if (followLinks) {
140+ Object key = attrs.fileKey();
141+
142+ // if this directory and ancestor has a file key then we compare
143+ // them; otherwise we use less efficient isSameFile test.
144+ for (AncestorDirectory ancestor: ancestors) {
145+ Object ancestorKey = ancestor.fileKey();
146+ if (key != null && ancestorKey != null) {
147+ if (key.equals(ancestorKey)) {
148+ // cycle detected
149+ return visitor.visitFileFailed(file,
150+ new FileSystemLoopException(file.toString()));
151+ }
152+ } else {
153+ boolean isSameFile = false;
154+ try {
155+ isSameFile = Files.isSameFile(file, ancestor.file());
156+ } catch (IOException x) {
157+ // ignore
158+ } catch (SecurityException x) {
159+ // ignore
160+ }
161+ if (isSameFile) {
162+ // cycle detected
163+ return visitor.visitFileFailed(file,
164+ new FileSystemLoopException(file.toString()));
165+ }
166+ }
167+ }
168+
169+ ancestors.add(new AncestorDirectory(file, key));
170+ }
171+
172+ // visit directory
173+ try {
174+ DirectoryStream<Path> stream = null;
175+ FileVisitResult result;
176+
177+ // open the directory
178+ try {
179+ stream = Files.newDirectoryStream(file);
180+ } catch (IOException x) {
181+ return visitor.visitFileFailed(file, x);
182+ } catch (SecurityException x) {
183+ // ignore, as per spec
184+ return FileVisitResult.CONTINUE;
185+ }
186+
187+ // the exception notified to the postVisitDirectory method
188+ IOException ioe = null;
189+
190+ // invoke preVisitDirectory and then visit each entry
191+ try {
192+ result = visitor.preVisitDirectory(file, attrs);
193+ if (result != FileVisitResult.CONTINUE) {
194+ return result;
195+ }
196+
197+ try {
198+ for (Path entry: stream) {
199+ result = walk(entry, depth+1, ancestors);
200+
201+ // returning null will cause NPE to be thrown
202+ if (result == null || result == FileVisitResult.TERMINATE)
203+ return result;
204+
205+ // skip remaining siblings in this directory
206+ if (result == FileVisitResult.SKIP_SIBLINGS)
207+ break;
208+ }
209+ } catch (DirectoryIteratorException e) {
210+ // IOException will be notified to postVisitDirectory
211+ ioe = e.getCause();
212+ }
213+ } finally {
214+ try {
215+ stream.close();
216+ } catch (IOException e) {
217+ // IOException will be notified to postVisitDirectory
218+ if (ioe == null)
219+ ioe = e;
220+ }
221+ }
222+
223+ // invoke postVisitDirectory last
224+ return visitor.postVisitDirectory(file, ioe);
225+
226+ } finally {
227+ // remove key from trail if doing cycle detection
228+ if (followLinks) {
229+ ancestors.remove(ancestors.size()-1);
230+ }
231+ }
232+ }
233+
234+ private static class AncestorDirectory {
235+ private final Path dir;
236+ private final Object key;
237+ AncestorDirectory(Path dir, Object key) {
238+ this.dir = dir;
239+ this.key = key;
240+ }
241+ Path file() {
242+ return dir;
243+ }
244+ Object fileKey() {
245+ return key;
246+ }
247+ }
248+}