blob: dd3e05ef0c85d3ee843eb51a720b070a513bd9ab [file] [log] [blame]
Shubham Ajmerae6bac4b2016-05-20 15:27:50 +01001/*
2 * Copyright (c) 2008, 2010, 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
26package sun.nio.fs;
27
28import java.nio.file.*;
29import java.util.Iterator;
30import java.util.NoSuchElementException;
31import java.util.concurrent.locks.*;
32import java.io.IOException;
Shubham Ajmera573d9912016-10-24 11:48:28 +010033
34import dalvik.system.CloseGuard;
35
Shubham Ajmerae6bac4b2016-05-20 15:27:50 +010036import static sun.nio.fs.UnixNativeDispatcher.*;
37
38/**
39 * Unix implementation of java.nio.file.DirectoryStream
40 */
41
42class UnixDirectoryStream
43 implements DirectoryStream<Path>
44{
45 // path to directory when originally opened
46 private final UnixPath dir;
47
48 // directory pointer (returned by opendir)
49 private final long dp;
50
51 // filter (may be null)
52 private final DirectoryStream.Filter<? super Path> filter;
53
54 // used to coorindate closing of directory stream
55 private final ReentrantReadWriteLock streamLock =
56 new ReentrantReadWriteLock(true);
57
58 // indicates if directory stream is open (synchronize on closeLock)
59 private volatile boolean isClosed;
60
61 // directory iterator
62 private Iterator<Path> iterator;
63
Shubham Ajmera573d9912016-10-24 11:48:28 +010064 // Android-changed: Add CloseGuard support.
65 private final CloseGuard guard = CloseGuard.get();
66
Shubham Ajmerae6bac4b2016-05-20 15:27:50 +010067 /**
68 * Initializes a new instance
69 */
70 UnixDirectoryStream(UnixPath dir, long dp, DirectoryStream.Filter<? super Path> filter) {
71 this.dir = dir;
72 this.dp = dp;
73 this.filter = filter;
Shubham Ajmera573d9912016-10-24 11:48:28 +010074
75 // Android-changed: Add CloseGuard support.
76 guard.open("close");
Shubham Ajmerae6bac4b2016-05-20 15:27:50 +010077 }
78
79 protected final UnixPath directory() {
80 return dir;
81 }
82
83 protected final Lock readLock() {
84 return streamLock.readLock();
85 }
86
87 protected final Lock writeLock() {
88 return streamLock.writeLock();
89 }
90
91 protected final boolean isOpen() {
92 return !isClosed;
93 }
94
95 protected final boolean closeImpl() throws IOException {
96 if (!isClosed) {
97 isClosed = true;
98 try {
99 closedir(dp);
100 } catch (UnixException x) {
101 throw new IOException(x.errorString());
102 }
Shubham Ajmera573d9912016-10-24 11:48:28 +0100103
104 // Android-changed: Add CloseGuard support.
105 guard.close();
Shubham Ajmerae6bac4b2016-05-20 15:27:50 +0100106 return true;
107 } else {
108 return false;
109 }
110 }
111
112 @Override
113 public void close()
114 throws IOException
115 {
116 writeLock().lock();
117 try {
118 closeImpl();
119 } finally {
120 writeLock().unlock();
121 }
122 }
123
124 protected final Iterator<Path> iterator(DirectoryStream<Path> ds) {
125 if (isClosed) {
126 throw new IllegalStateException("Directory stream is closed");
127 }
128 synchronized (this) {
129 if (iterator != null)
130 throw new IllegalStateException("Iterator already obtained");
131 iterator = new UnixDirectoryIterator(ds);
132 return iterator;
133 }
134 }
135
136 @Override
137 public Iterator<Path> iterator() {
138 return iterator(this);
139 }
140
141 /**
142 * Iterator implementation
143 */
144 private class UnixDirectoryIterator implements Iterator<Path> {
145 private final DirectoryStream<Path> stream;
146
147 // true when at EOF
148 private boolean atEof;
149
150 // next entry to return
151 private Path nextEntry;
152
153 UnixDirectoryIterator(DirectoryStream<Path> stream) {
154 atEof = false;
155 this.stream = stream;
156 }
157
158 // Return true if file name is "." or ".."
159 private boolean isSelfOrParent(byte[] nameAsBytes) {
160 if (nameAsBytes[0] == '.') {
161 if ((nameAsBytes.length == 1) ||
162 (nameAsBytes.length == 2 && nameAsBytes[1] == '.')) {
163 return true;
164 }
165 }
166 return false;
167 }
168
169 // Returns next entry (or null)
170 private Path readNextEntry() {
171 assert Thread.holdsLock(this);
172
173 for (;;) {
174 byte[] nameAsBytes = null;
175
176 // prevent close while reading
177 readLock().lock();
178 try {
179 if (isOpen()) {
180 nameAsBytes = readdir(dp);
181 }
182 } catch (UnixException x) {
183 IOException ioe = x.asIOException(dir);
184 throw new DirectoryIteratorException(ioe);
185 } finally {
186 readLock().unlock();
187 }
188
189 // EOF
190 if (nameAsBytes == null) {
191 atEof = true;
192 return null;
193 }
194
195 // ignore "." and ".."
196 if (!isSelfOrParent(nameAsBytes)) {
197 Path entry = dir.resolve(nameAsBytes);
198
199 // return entry if no filter or filter accepts it
200 try {
201 if (filter == null || filter.accept(entry))
202 return entry;
203 } catch (IOException ioe) {
204 throw new DirectoryIteratorException(ioe);
205 }
206 }
207 }
208 }
209
210 @Override
211 public synchronized boolean hasNext() {
212 if (nextEntry == null && !atEof)
213 nextEntry = readNextEntry();
214 return nextEntry != null;
215 }
216
217 @Override
218 public synchronized Path next() {
219 Path result;
220 if (nextEntry == null && !atEof) {
221 result = readNextEntry();
222 } else {
223 result = nextEntry;
224 nextEntry = null;
225 }
226 if (result == null)
227 throw new NoSuchElementException();
228 return result;
229 }
230
231 @Override
232 public void remove() {
233 throw new UnsupportedOperationException();
234 }
235 }
Shubham Ajmera573d9912016-10-24 11:48:28 +0100236
237 /**
238 * Cleans up if the user forgets to close it.
239 */
240 // Android-changed: Add CloseGuard support.
241 protected void finalize() throws IOException {
242 if (guard != null) {
243 guard.warnIfOpen();
244 }
245
246 close();
247 }
Shubham Ajmerae6bac4b2016-05-20 15:27:50 +0100248}