jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java
changeset 2057 3acf8e5e2ca0
child 3065 452aaa2899fc
equal deleted inserted replaced
2056:115e09b7a004 2057:3acf8e5e2ca0
       
     1 /*
       
     2  * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.nio.fs;
       
    27 
       
    28 import java.nio.file.*;
       
    29 import java.util.Iterator;
       
    30 import java.util.ConcurrentModificationException;
       
    31 import java.util.NoSuchElementException;
       
    32 import java.util.concurrent.locks.*;
       
    33 import java.io.IOException;
       
    34 import static sun.nio.fs.UnixNativeDispatcher.*;
       
    35 
       
    36 /**
       
    37  * Unix implementation of java.nio.file.DirectoryStream
       
    38  */
       
    39 
       
    40 class UnixDirectoryStream
       
    41     implements DirectoryStream<Path>
       
    42 {
       
    43     // path to directory when originally opened
       
    44     private final UnixPath dir;
       
    45 
       
    46     // directory pointer (returned by opendir)
       
    47     private final long dp;
       
    48 
       
    49     // filter (may be null)
       
    50     private final DirectoryStream.Filter<? super Path> filter;
       
    51 
       
    52     // used to coorindate closing of directory stream
       
    53     private final ReentrantReadWriteLock streamLock =
       
    54         new ReentrantReadWriteLock(true);
       
    55 
       
    56     // indicates if directory stream is open (synchronize on closeLock)
       
    57     private volatile boolean isClosed;
       
    58 
       
    59     // directory iterator
       
    60     private Iterator<Path> iterator;
       
    61 
       
    62     /**
       
    63      * Initializes a new instance
       
    64      */
       
    65     UnixDirectoryStream(UnixPath dir, long dp, DirectoryStream.Filter<? super Path> filter) {
       
    66         this.dir = dir;
       
    67         this.dp = dp;
       
    68         this.filter = filter;
       
    69     }
       
    70 
       
    71     protected final UnixPath directory() {
       
    72         return dir;
       
    73     }
       
    74 
       
    75     protected final Lock readLock() {
       
    76         return streamLock.readLock();
       
    77     }
       
    78 
       
    79     protected final Lock writeLock() {
       
    80         return streamLock.writeLock();
       
    81     }
       
    82 
       
    83     protected final boolean isOpen() {
       
    84         return !isClosed;
       
    85     }
       
    86 
       
    87     protected final boolean closeImpl() throws IOException {
       
    88         if (!isClosed) {
       
    89             isClosed = true;
       
    90             try {
       
    91                 closedir(dp);
       
    92             } catch (UnixException x) {
       
    93                 throw new IOException(x.errorString());
       
    94             }
       
    95             return true;
       
    96         } else {
       
    97             return false;
       
    98         }
       
    99     }
       
   100 
       
   101     @Override
       
   102     public void close()
       
   103         throws IOException
       
   104     {
       
   105         writeLock().lock();
       
   106         try {
       
   107             closeImpl();
       
   108         } finally {
       
   109             writeLock().unlock();
       
   110         }
       
   111     }
       
   112 
       
   113     protected final Iterator<Path> iterator(DirectoryStream<Path> ds) {
       
   114         if (isClosed) {
       
   115             throw new IllegalStateException("Directory stream is closed");
       
   116         }
       
   117         synchronized (this) {
       
   118             if (iterator != null)
       
   119                 throw new IllegalStateException("Iterator already obtained");
       
   120             iterator = new UnixDirectoryIterator(ds);
       
   121             return iterator;
       
   122         }
       
   123     }
       
   124 
       
   125     @Override
       
   126     public Iterator<Path> iterator() {
       
   127         return iterator(this);
       
   128     }
       
   129 
       
   130     /**
       
   131      * Iterator implementation
       
   132      */
       
   133     private class UnixDirectoryIterator implements Iterator<Path> {
       
   134         private final DirectoryStream<Path> stream;
       
   135 
       
   136         // true when at EOF
       
   137         private boolean atEof;
       
   138 
       
   139         // next entry to return
       
   140         private Path nextEntry;
       
   141 
       
   142         // previous entry returned by next method (needed by remove method)
       
   143         private Path prevEntry;
       
   144 
       
   145         UnixDirectoryIterator(DirectoryStream<Path> stream) {
       
   146             atEof = false;
       
   147             this.stream = stream;
       
   148         }
       
   149 
       
   150         // Return true if file name is "." or ".."
       
   151         private boolean isSelfOrParent(byte[] nameAsBytes) {
       
   152             if (nameAsBytes[0] == '.') {
       
   153                 if ((nameAsBytes.length == 1) ||
       
   154                     (nameAsBytes.length == 2 && nameAsBytes[1] == '.')) {
       
   155                     return true;
       
   156                 }
       
   157             }
       
   158             return false;
       
   159         }
       
   160 
       
   161         // Returns next entry (or null)
       
   162         private Path readNextEntry() {
       
   163             assert Thread.holdsLock(this);
       
   164 
       
   165             for (;;) {
       
   166                 byte[] nameAsBytes = null;
       
   167 
       
   168                 // prevent close while reading
       
   169                 readLock().lock();
       
   170                 try {
       
   171                     if (isClosed)
       
   172                         throwAsConcurrentModificationException(new
       
   173                             ClosedDirectoryStreamException());
       
   174                     try {
       
   175                         nameAsBytes = readdir(dp);
       
   176                     } catch (UnixException x) {
       
   177                         try {
       
   178                             x.rethrowAsIOException(dir);
       
   179                         } catch (IOException ioe) {
       
   180                             throwAsConcurrentModificationException(ioe);
       
   181                         }
       
   182                     }
       
   183                 } finally {
       
   184                     readLock().unlock();
       
   185                 }
       
   186 
       
   187                 // EOF
       
   188                 if (nameAsBytes == null) {
       
   189                     return null;
       
   190                 }
       
   191 
       
   192                 // ignore "." and ".."
       
   193                 if (!isSelfOrParent(nameAsBytes)) {
       
   194                     Path entry = dir.resolve(nameAsBytes);
       
   195 
       
   196                     // return entry if no filter or filter accepts it
       
   197                     if (filter.accept(entry)) {
       
   198                         return entry;
       
   199                     }
       
   200                 }
       
   201             }
       
   202         }
       
   203 
       
   204         @Override
       
   205         public synchronized boolean hasNext() {
       
   206             if (nextEntry == null && !atEof) {
       
   207                 nextEntry = readNextEntry();
       
   208 
       
   209                 // at EOF?
       
   210                 if (nextEntry == null)
       
   211                     atEof = true;
       
   212             }
       
   213             return nextEntry != null;
       
   214         }
       
   215 
       
   216         @Override
       
   217         public synchronized Path next() {
       
   218             if (nextEntry == null) {
       
   219                 if (!atEof) {
       
   220                     nextEntry = readNextEntry();
       
   221                 }
       
   222                 if (nextEntry == null) {
       
   223                     atEof = true;
       
   224                     throw new NoSuchElementException();
       
   225                 }
       
   226             }
       
   227             prevEntry = nextEntry;
       
   228             nextEntry = null;
       
   229             return prevEntry;
       
   230         }
       
   231 
       
   232         @Override
       
   233         public void remove() {
       
   234             if (isClosed) {
       
   235                 throw new ClosedDirectoryStreamException();
       
   236             }
       
   237             Path entry;
       
   238             synchronized (this) {
       
   239                 if (prevEntry == null)
       
   240                     throw new IllegalStateException("No previous entry to remove");
       
   241                 entry = prevEntry;
       
   242                 prevEntry = null;
       
   243             }
       
   244 
       
   245             // use (race-free) unlinkat if available
       
   246             try {
       
   247                 if (stream instanceof UnixSecureDirectoryStream) {
       
   248                     ((UnixSecureDirectoryStream)stream)
       
   249                         .implDelete(entry.getName(), false, 0);
       
   250                 } else {
       
   251                     entry.delete(true);
       
   252                 }
       
   253             } catch (IOException ioe) {
       
   254                 throwAsConcurrentModificationException(ioe);
       
   255             } catch (SecurityException se) {
       
   256                 throwAsConcurrentModificationException(se);
       
   257             }
       
   258         }
       
   259     }
       
   260 
       
   261     private static void throwAsConcurrentModificationException(Throwable t) {
       
   262         ConcurrentModificationException cme = new ConcurrentModificationException();
       
   263         cme.initCause(t);
       
   264         throw cme;
       
   265     }
       
   266 
       
   267 }