1 /* 2 * Copyright (c) 2008, 2020, 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.net.URI; 29 import java.net.URISyntaxException; 30 31 /** 32 * Utility methods to convert between Path and URIs. 33 */ 34 35 class WindowsUriSupport { WindowsUriSupport()36 private WindowsUriSupport() { 37 } 38 39 // suffix for IPv6 literal address 40 private static final String IPV6_LITERAL_SUFFIX = ".ipv6-literal.net"; 41 42 /** 43 * Returns URI to represent the given (absolute) path 44 */ toUri(String path, boolean isUnc, boolean addSlash)45 private static URI toUri(String path, boolean isUnc, boolean addSlash) { 46 String uriHost; 47 String uriPath; 48 49 if (isUnc) { 50 int slash = path.indexOf('\\', 2); 51 uriHost = path.substring(2, slash); 52 uriPath = path.substring(slash).replace('\\', '/'); 53 54 // handle IPv6 literal addresses 55 // 1. drop .ivp6-literal.net 56 // 2. replace "-" with ":" 57 // 3. replace "s" with "%" (zone/scopeID delimiter) 58 if (uriHost.endsWith(IPV6_LITERAL_SUFFIX)) { 59 uriHost = uriHost 60 .substring(0, uriHost.length() - IPV6_LITERAL_SUFFIX.length()) 61 .replace('-', ':') 62 .replace('s', '%'); 63 } 64 } else { 65 uriHost = ""; 66 uriPath = "/" + path.replace('\\', '/'); 67 } 68 69 // append slash if known to be directory 70 if (addSlash) 71 uriPath += "/"; 72 73 // return file:///C:/My%20Documents or file://server/share/foo 74 try { 75 return new URI("file", uriHost, uriPath, null); 76 } catch (URISyntaxException x) { 77 if (!isUnc) 78 throw new AssertionError(x); 79 } 80 81 // if we get here it means we've got a UNC with reserved characters 82 // in the server name. The authority component cannot contain escaped 83 // octets so fallback to encoding the server name into the URI path 84 // component. 85 uriPath = "//" + path.replace('\\', '/'); 86 if (addSlash) 87 uriPath += "/"; 88 try { 89 return new URI("file", null, uriPath, null); 90 } catch (URISyntaxException x) { 91 throw new AssertionError(x); 92 } 93 } 94 95 /** 96 * Converts given Path to a URI 97 */ toUri(WindowsPath path)98 static URI toUri(WindowsPath path) { 99 path = path.toAbsolutePath(); 100 String s = path.toString(); 101 102 // trailing slash will be added if file is a directory. Skip check if 103 // already have trailing space 104 boolean addSlash = false; 105 if (!s.endsWith("\\")) { 106 try { 107 path.checkRead(); 108 addSlash = WindowsFileAttributes.get(path, true).isDirectory(); 109 } catch (SecurityException | WindowsException x) { 110 } 111 } 112 113 return toUri(s, path.isUnc(), addSlash); 114 } 115 116 /** 117 * Converts given URI to a Path 118 */ fromUri(WindowsFileSystem fs, URI uri)119 static WindowsPath fromUri(WindowsFileSystem fs, URI uri) { 120 if (!uri.isAbsolute()) 121 throw new IllegalArgumentException("URI is not absolute"); 122 if (uri.isOpaque()) 123 throw new IllegalArgumentException("URI is not hierarchical"); 124 String scheme = uri.getScheme(); 125 if ((scheme == null) || !scheme.equalsIgnoreCase("file")) 126 throw new IllegalArgumentException("URI scheme is not \"file\""); 127 if (uri.getRawFragment() != null) 128 throw new IllegalArgumentException("URI has a fragment component"); 129 if (uri.getRawQuery() != null) 130 throw new IllegalArgumentException("URI has a query component"); 131 String path = uri.getPath(); 132 if (path.isEmpty()) 133 throw new IllegalArgumentException("URI path component is empty"); 134 135 // UNC 136 String auth = uri.getRawAuthority(); 137 if (auth != null && !auth.isEmpty()) { 138 String host = uri.getHost(); 139 if (host == null) 140 throw new IllegalArgumentException("URI authority component has undefined host"); 141 if (uri.getUserInfo() != null) 142 throw new IllegalArgumentException("URI authority component has user-info"); 143 if (uri.getPort() != -1) 144 throw new IllegalArgumentException("URI authority component has port number"); 145 146 // IPv6 literal 147 // 1. drop enclosing brackets 148 // 2. replace ":" with "-" 149 // 3. replace "%" with "s" (zone/scopeID delimiter) 150 // 4. Append .ivp6-literal.net 151 if (host.startsWith("[")) { 152 host = host.substring(1, host.length()-1) 153 .replace(':', '-') 154 .replace('%', 's'); 155 host += IPV6_LITERAL_SUFFIX; 156 } 157 158 // reconstitute the UNC 159 path = "\\\\" + host + path; 160 } else { 161 if ((path.length() > 2) && (path.charAt(2) == ':')) { 162 // "/c:/foo" --> "c:/foo" 163 path = path.substring(1); 164 } 165 } 166 return WindowsPath.parse(fs, path); 167 } 168 } 169