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