25 |
25 |
26 package sun.nio.fs; |
26 package sun.nio.fs; |
27 |
27 |
28 import java.nio.file.*; |
28 import java.nio.file.*; |
29 import java.util.Iterator; |
29 import java.util.Iterator; |
30 import java.util.ConcurrentModificationException; |
|
31 import java.util.NoSuchElementException; |
30 import java.util.NoSuchElementException; |
32 import java.util.concurrent.locks.*; |
31 import java.util.concurrent.locks.*; |
33 import java.io.IOException; |
32 import java.io.IOException; |
34 import static sun.nio.fs.UnixNativeDispatcher.*; |
33 import static sun.nio.fs.UnixNativeDispatcher.*; |
35 |
34 |
137 private boolean atEof; |
136 private boolean atEof; |
138 |
137 |
139 // next entry to return |
138 // next entry to return |
140 private Path nextEntry; |
139 private Path nextEntry; |
141 |
140 |
142 // previous entry returned by next method (needed by remove method) |
|
143 private Path prevEntry; |
|
144 |
|
145 UnixDirectoryIterator(DirectoryStream<Path> stream) { |
141 UnixDirectoryIterator(DirectoryStream<Path> stream) { |
146 atEof = false; |
142 atEof = false; |
147 this.stream = stream; |
143 this.stream = stream; |
148 } |
144 } |
149 |
145 |
166 byte[] nameAsBytes = null; |
162 byte[] nameAsBytes = null; |
167 |
163 |
168 // prevent close while reading |
164 // prevent close while reading |
169 readLock().lock(); |
165 readLock().lock(); |
170 try { |
166 try { |
171 if (isClosed) |
167 if (isOpen()) { |
172 throwAsConcurrentModificationException(new |
|
173 ClosedDirectoryStreamException()); |
|
174 try { |
|
175 nameAsBytes = readdir(dp); |
168 nameAsBytes = readdir(dp); |
176 } catch (UnixException x) { |
|
177 try { |
|
178 x.rethrowAsIOException(dir); |
|
179 } catch (IOException ioe) { |
|
180 throwAsConcurrentModificationException(ioe); |
|
181 } |
|
182 } |
169 } |
|
170 } catch (UnixException x) { |
|
171 IOException ioe = x.asIOException(dir); |
|
172 throw new DirectoryIteratorException(ioe); |
183 } finally { |
173 } finally { |
184 readLock().unlock(); |
174 readLock().unlock(); |
185 } |
175 } |
186 |
176 |
187 // EOF |
177 // EOF |
188 if (nameAsBytes == null) { |
178 if (nameAsBytes == null) { |
|
179 atEof = true; |
189 return null; |
180 return null; |
190 } |
181 } |
191 |
182 |
192 // ignore "." and ".." |
183 // ignore "." and ".." |
193 if (!isSelfOrParent(nameAsBytes)) { |
184 if (!isSelfOrParent(nameAsBytes)) { |
196 // return entry if no filter or filter accepts it |
187 // return entry if no filter or filter accepts it |
197 try { |
188 try { |
198 if (filter == null || filter.accept(entry)) |
189 if (filter == null || filter.accept(entry)) |
199 return entry; |
190 return entry; |
200 } catch (IOException ioe) { |
191 } catch (IOException ioe) { |
201 throwAsConcurrentModificationException(ioe); |
192 throw new DirectoryIteratorException(ioe); |
202 } |
193 } |
203 } |
194 } |
204 } |
195 } |
205 } |
196 } |
206 |
197 |
207 @Override |
198 @Override |
208 public synchronized boolean hasNext() { |
199 public synchronized boolean hasNext() { |
209 if (nextEntry == null && !atEof) { |
200 if (nextEntry == null && !atEof) |
210 nextEntry = readNextEntry(); |
201 nextEntry = readNextEntry(); |
211 |
|
212 // at EOF? |
|
213 if (nextEntry == null) |
|
214 atEof = true; |
|
215 } |
|
216 return nextEntry != null; |
202 return nextEntry != null; |
217 } |
203 } |
218 |
204 |
219 @Override |
205 @Override |
220 public synchronized Path next() { |
206 public synchronized Path next() { |
221 if (nextEntry == null) { |
207 Path result; |
222 if (!atEof) { |
208 if (nextEntry == null && !atEof) { |
223 nextEntry = readNextEntry(); |
209 result = readNextEntry(); |
224 } |
210 } else { |
225 if (nextEntry == null) { |
211 result = nextEntry; |
226 atEof = true; |
212 nextEntry = null; |
227 throw new NoSuchElementException(); |
213 } |
228 } |
214 if (result == null) |
229 } |
215 throw new NoSuchElementException(); |
230 prevEntry = nextEntry; |
216 return result; |
231 nextEntry = null; |
|
232 return prevEntry; |
|
233 } |
217 } |
234 |
218 |
235 @Override |
219 @Override |
236 public void remove() { |
220 public void remove() { |
237 if (isClosed) { |
221 throw new UnsupportedOperationException(); |
238 throwAsConcurrentModificationException(new |
222 } |
239 ClosedDirectoryStreamException()); |
223 } |
240 } |
|
241 Path entry; |
|
242 synchronized (this) { |
|
243 if (prevEntry == null) |
|
244 throw new IllegalStateException("No previous entry to remove"); |
|
245 entry = prevEntry; |
|
246 prevEntry = null; |
|
247 } |
|
248 |
|
249 // use (race-free) unlinkat if available |
|
250 try { |
|
251 if (stream instanceof UnixSecureDirectoryStream) { |
|
252 ((UnixSecureDirectoryStream)stream) |
|
253 .implDelete(entry.getName(), false, 0); |
|
254 } else { |
|
255 entry.delete(); |
|
256 } |
|
257 } catch (IOException ioe) { |
|
258 throwAsConcurrentModificationException(ioe); |
|
259 } catch (SecurityException se) { |
|
260 throwAsConcurrentModificationException(se); |
|
261 } |
|
262 } |
|
263 } |
|
264 |
|
265 private static void throwAsConcurrentModificationException(Throwable t) { |
|
266 ConcurrentModificationException cme = new ConcurrentModificationException(); |
|
267 cme.initCause(t); |
|
268 throw cme; |
|
269 } |
|
270 |
|
271 } |
224 } |