/*
 * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.nio.fs;

import java.nio.file.*;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.locks.*;
import java.io.IOException;
import static sun.nio.fs.UnixNativeDispatcher.*;

Unix implementation of java.nio.file.DirectoryStream
/** * Unix implementation of java.nio.file.DirectoryStream */
class UnixDirectoryStream implements DirectoryStream<Path> { // path to directory when originally opened private final UnixPath dir; // directory pointer (returned by opendir) private final long dp; // filter (may be null) private final DirectoryStream.Filter<? super Path> filter; // used to coordinate closing of directory stream private final ReentrantReadWriteLock streamLock = new ReentrantReadWriteLock(true); // indicates if directory stream is open (synchronize on closeLock) private volatile boolean isClosed; // directory iterator private Iterator<Path> iterator;
Initializes a new instance
/** * Initializes a new instance */
UnixDirectoryStream(UnixPath dir, long dp, DirectoryStream.Filter<? super Path> filter) { this.dir = dir; this.dp = dp; this.filter = filter; } protected final UnixPath directory() { return dir; } protected final Lock readLock() { return streamLock.readLock(); } protected final Lock writeLock() { return streamLock.writeLock(); } protected final boolean isOpen() { return !isClosed; } protected final boolean closeImpl() throws IOException { if (!isClosed) { isClosed = true; try { closedir(dp); } catch (UnixException x) { throw new IOException(x.errorString()); } return true; } else { return false; } } @Override public void close() throws IOException { writeLock().lock(); try { closeImpl(); } finally { writeLock().unlock(); } } protected final Iterator<Path> iterator(DirectoryStream<Path> ds) { if (isClosed) { throw new IllegalStateException("Directory stream is closed"); } synchronized (this) { if (iterator != null) throw new IllegalStateException("Iterator already obtained"); iterator = new UnixDirectoryIterator(); return iterator; } } @Override public Iterator<Path> iterator() { return iterator(this); }
Iterator implementation
/** * Iterator implementation */
private class UnixDirectoryIterator implements Iterator<Path> { // true when at EOF private boolean atEof; // next entry to return private Path nextEntry; UnixDirectoryIterator() { atEof = false; } // Return true if file name is "." or ".." private boolean isSelfOrParent(byte[] nameAsBytes) { if (nameAsBytes[0] == '.') { if ((nameAsBytes.length == 1) || (nameAsBytes.length == 2 && nameAsBytes[1] == '.')) { return true; } } return false; } // Returns next entry (or null) private Path readNextEntry() { assert Thread.holdsLock(this); for (;;) { byte[] nameAsBytes = null; // prevent close while reading readLock().lock(); try { if (isOpen()) { nameAsBytes = readdir(dp); } } catch (UnixException x) { IOException ioe = x.asIOException(dir); throw new DirectoryIteratorException(ioe); } finally { readLock().unlock(); } // EOF if (nameAsBytes == null) { atEof = true; return null; } // ignore "." and ".." if (!isSelfOrParent(nameAsBytes)) { Path entry = dir.resolve(nameAsBytes); // return entry if no filter or filter accepts it try { if (filter == null || filter.accept(entry)) return entry; } catch (IOException ioe) { throw new DirectoryIteratorException(ioe); } } } } @Override public synchronized boolean hasNext() { if (nextEntry == null && !atEof) nextEntry = readNextEntry(); return nextEntry != null; } @Override public synchronized Path next() { Path result; if (nextEntry == null && !atEof) { result = readNextEntry(); } else { result = nextEntry; nextEntry = null; } if (result == null) throw new NoSuchElementException(); return result; } @Override public void remove() { throw new UnsupportedOperationException(); } } }