1 /*
   2  * Copyright (c) 2008, 2015, 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 sun.nio.fs;
  27 
  28 import java.nio.file.*;
  29 import java.nio.file.attribute.*;
  30 import java.nio.file.spi.*;
  31 import java.util.*;
  32 import java.util.regex.Pattern;
  33 import java.io.IOException;
  34 
  35 class WindowsFileSystem
  36     extends FileSystem
  37 {
  38     private final WindowsFileSystemProvider provider;
  39 
  40     // default directory (is absolute), and default root
  41     private final String defaultDirectory;
  42     private final String defaultRoot;
  43 
  44     // package-private
  45     WindowsFileSystem(WindowsFileSystemProvider provider,
  46                       String dir)
  47     {
  48         this.provider = provider;
  49 
  50         // parse default directory and check it is absolute
  51         WindowsPathParser.Result result = WindowsPathParser.parse(dir);
  52 
  53         if ((result.type() != WindowsPathType.ABSOLUTE) &&
  54             (result.type() != WindowsPathType.UNC))
  55             throw new AssertionError("Default directory is not an absolute path");
  56         this.defaultDirectory = result.path();
  57         this.defaultRoot = result.root();
  58     }
  59 
  60     // package-private
  61     String defaultDirectory() {
  62         return defaultDirectory;
  63     }
  64 
  65     String defaultRoot() {
  66         return defaultRoot;
  67     }
  68 
  69     @Override
  70     public FileSystemProvider provider() {
  71         return provider;
  72     }
  73 
  74     @Override
  75     public String getSeparator() {
  76         return "\\";
  77     }
  78 
  79     @Override
  80     public boolean isOpen() {
  81         return true;
  82     }
  83 
  84     @Override
  85     public boolean isReadOnly() {
  86         return false;
  87     }
  88 
  89     @Override
  90     public void close() throws IOException {
  91         throw new UnsupportedOperationException();
  92     }
  93 
  94     @Override
  95     public Iterable<Path> getRootDirectories() {
  96         int drives = 0;
  97         try {
  98             drives = WindowsNativeDispatcher.GetLogicalDrives();
  99         } catch (WindowsException x) {
 100             // shouldn't happen
 101             throw new AssertionError(x.getMessage());
 102         }
 103 
 104         // iterate over roots, ignoring those that the security manager denies
 105         ArrayList<Path> result = new ArrayList<>();
 106         SecurityManager sm = System.getSecurityManager();
 107         for (int i = 0; i <= 25; i++) {  // 0->A, 1->B, 2->C...
 108             if ((drives & (1 << i)) != 0) {
 109                 StringBuilder sb = new StringBuilder(3);
 110                 sb.append((char)('A' + i));
 111                 sb.append(":\\");
 112                 String root = sb.toString();
 113                 if (sm != null) {
 114                     try {
 115                         sm.checkRead(root);
 116                     } catch (SecurityException x) {
 117                         continue;
 118                     }
 119                 }
 120                 result.add(WindowsPath.createFromNormalizedPath(this, root));
 121             }
 122         }
 123         return Collections.unmodifiableList(result);
 124     }
 125 
 126     /**
 127      * Iterator returned by getFileStores method.
 128      */
 129     private class FileStoreIterator implements Iterator<FileStore> {
 130         private final Iterator<Path> roots;
 131         private FileStore next;
 132 
 133         FileStoreIterator() {
 134             this.roots = getRootDirectories().iterator();
 135         }
 136 
 137         private FileStore readNext() {
 138             assert Thread.holdsLock(this);
 139             for (;;) {
 140                 if (!roots.hasNext())
 141                     return null;
 142                 WindowsPath root = (WindowsPath)roots.next();
 143                 // ignore if security manager denies access
 144                 try {
 145                     root.checkRead();
 146                 } catch (SecurityException x) {
 147                     continue;
 148                 }
 149                 try {
 150                     FileStore fs = WindowsFileStore.create(root.toString(), true);
 151                     if (fs != null)
 152                         return fs;
 153                 } catch (IOException ioe) {
 154                     // skip it
 155                 }
 156             }
 157         }
 158 
 159         @Override
 160         public synchronized boolean hasNext() {
 161             if (next != null)
 162                 return true;
 163             next = readNext();
 164             return next != null;
 165         }
 166 
 167         @Override
 168         public synchronized FileStore next() {
 169             if (next == null)
 170                 next = readNext();
 171             if (next == null) {
 172                 throw new NoSuchElementException();
 173             } else {
 174                 FileStore result = next;
 175                 next = null;
 176                 return result;
 177             }
 178         }
 179 
 180         @Override
 181         public void remove() {
 182             throw new UnsupportedOperationException();
 183         }
 184     }
 185 
 186     @Override
 187     public Iterable<FileStore> getFileStores() {
 188         SecurityManager sm = System.getSecurityManager();
 189         if (sm != null) {
 190             try {
 191                 sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
 192             } catch (SecurityException se) {
 193                 return Collections.emptyList();
 194             }
 195         }
 196         return new Iterable<FileStore>() {
 197             public Iterator<FileStore> iterator() {
 198                 return new FileStoreIterator();
 199             }
 200         };
 201     }
 202 
 203     // supported views
 204     private static final Set<String> supportedFileAttributeViews = Collections
 205         .unmodifiableSet(new HashSet<String>(Arrays.asList("basic", "dos", "acl", "owner", "user")));
 206 
 207     @Override
 208     public Set<String> supportedFileAttributeViews() {
 209         return supportedFileAttributeViews;
 210     }
 211 
 212     @Override
 213     public final Path getPath(String first, String... more) {
 214         String path;
 215         if (more.length == 0) {
 216             path = first;
 217         } else {
 218             StringBuilder sb = new StringBuilder();
 219             sb.append(first);
 220             for (String segment: more) {
 221                 if (!segment.isEmpty()) {
 222                     if (sb.length() > 0)
 223                         sb.append('\\');
 224                     sb.append(segment);
 225                 }
 226             }
 227             path = sb.toString();
 228         }
 229         return WindowsPath.parse(this, path);
 230     }
 231 
 232     @Override
 233     public UserPrincipalLookupService getUserPrincipalLookupService() {
 234         return LookupService.instance;
 235     }
 236 
 237     private static class LookupService {
 238         static final UserPrincipalLookupService instance =
 239             new UserPrincipalLookupService() {
 240                 @Override
 241                 public UserPrincipal lookupPrincipalByName(String name)
 242                     throws IOException
 243                 {
 244                     return WindowsUserPrincipals.lookup(name);
 245                 }
 246                 @Override
 247                 public GroupPrincipal lookupPrincipalByGroupName(String group)
 248                     throws IOException
 249                 {
 250                     UserPrincipal user = WindowsUserPrincipals.lookup(group);
 251                     if (!(user instanceof GroupPrincipal))
 252                         throw new UserPrincipalNotFoundException(group);
 253                     return (GroupPrincipal)user;
 254                 }
 255             };
 256     }
 257 
 258     @Override
 259     public PathMatcher getPathMatcher(String syntaxAndInput) {
 260         int pos = syntaxAndInput.indexOf(':');
 261         if (pos <= 0 || pos == syntaxAndInput.length())
 262             throw new IllegalArgumentException();
 263         String syntax = syntaxAndInput.substring(0, pos);
 264         String input = syntaxAndInput.substring(pos+1);
 265 
 266         String expr;
 267         if (syntax.equalsIgnoreCase(GLOB_SYNTAX)) {
 268             expr = Globs.toWindowsRegexPattern(input);
 269         } else {
 270             if (syntax.equalsIgnoreCase(REGEX_SYNTAX)) {
 271                 expr = input;
 272             } else {
 273                 throw new UnsupportedOperationException("Syntax '" + syntax +
 274                     "' not recognized");
 275             }
 276         }
 277 
 278         // match in unicode_case_insensitive
 279         final Pattern pattern = Pattern.compile(expr,
 280             Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
 281 
 282         // return matcher
 283         return new PathMatcher() {
 284             @Override
 285             public boolean matches(Path path) {
 286                 return pattern.matcher(path.toString()).matches();
 287             }
 288         };
 289     }
 290     private static final String GLOB_SYNTAX = "glob";
 291     private static final String REGEX_SYNTAX = "regex";
 292 
 293     @Override
 294     public WatchService newWatchService()
 295         throws IOException
 296     {
 297         return new WindowsWatchService(this);
 298     }
 299 }