141 } catch (NoSuchFileException exp) { 142 return false; 143 } 144 return true; 145 } 146 147 @Override 148 boolean isDirectory(byte[] path, boolean resolveLinks) 149 throws IOException { 150 NodeAndImage ni = checkNode(path); 151 return resolveLinks && ni.node.isLink() 152 ? ni.node.resolveLink(true).isDirectory() 153 : ni.node.isDirectory(); 154 } 155 156 @Override 157 Iterator<Path> iteratorOf(byte[] path, String childPrefix) 158 throws IOException { 159 NodeAndImage ni = checkNode(path); 160 Node node = ni.node.resolveLink(true); 161 162 if (!node.isDirectory()) { 163 throw new NotDirectoryException(getString(path)); 164 } 165 166 if (node.isRootDir()) { 167 return rootDirIterator(path, childPrefix); 168 } else if (node.isModulesDir()) { 169 return modulesDirIterator(path, childPrefix); 170 } else if (node.isPackagesDir()) { 171 return packagesDirIterator(path, childPrefix); 172 } 173 174 return nodesToIterator(toJrtPath(path), childPrefix, node.getChildren()); 175 } 176 177 @Override 178 byte[] getFileContent(byte[] path) throws IOException { 179 final NodeAndImage ni = checkResource(path); 180 return ni.getResource(); 181 } 182 183 // Implementation details below this point 184 // clean up this file system - called from finalize and close 185 private void cleanup() throws IOException { 186 if (!isOpen) { 187 return; 188 } 189 190 synchronized (this) { 191 isOpen = false; 192 193 // close all image reader and null out 194 bootImage.close(); 195 bootImage = null; 196 } 197 } 198 199 private static class NodeAndImage { 200 201 final Node node; 202 final ImageReader image; 203 204 NodeAndImage(Node node, ImageReader image) { 205 this.node = node; 206 this.image = image; 207 } 208 209 byte[] getResource() throws IOException { 210 return image.getResource(node); 211 } 212 } 213 214 private NodeAndImage lookup(byte[] path) { 215 ImageReader image = bootImage; 216 Node node; 217 try { 218 node = bootImage.findNode(path); 219 } catch (RuntimeException re) { 220 throw new InvalidPathException(getString(path), re.toString()); 221 } 222 return node != null ? new NodeAndImage(node, image) : null; 223 } 224 225 private NodeAndImage lookupSymbolic(byte[] path) { 226 for (int i = 1; i < path.length; i++) { 227 if (path[i] == (byte) '/') { 228 byte[] prefix = Arrays.copyOfRange(path, 0, i); 229 NodeAndImage ni = lookup(prefix); 230 if (ni == null) { 231 break; 232 } 233 234 if (ni.node.isLink()) { 235 Node link = ni.node.resolveLink(true); 236 // resolved symbolic path concatenated to the rest of the path 237 UTF8String resPath = link.getName().concat(new UTF8String(path, i)); 238 byte[] resPathBytes = resPath.getBytesCopy(); 239 ni = lookup(resPathBytes); 240 return ni != null ? ni : lookupSymbolic(resPathBytes); 241 } 242 } 243 } 244 245 return null; 246 } 247 248 private NodeAndImage findNode(byte[] path) throws IOException { 249 NodeAndImage ni = lookup(path); 250 if (ni == null) { 251 ni = lookupSymbolic(path); 252 if (ni == null) { 253 throw new NoSuchFileException(getString(path)); 254 } 255 } 256 return ni; 257 } 258 259 private NodeAndImage checkNode(byte[] path) throws IOException { 262 } 263 264 private NodeAndImage checkResource(byte[] path) throws IOException { 265 NodeAndImage ni = checkNode(path); 266 if (ni.node.isDirectory()) { 267 throw new FileSystemException(getString(path) + " is a directory"); 268 } 269 270 assert ni.node.isResource() : "resource node expected here"; 271 return ni; 272 } 273 274 private JrtPath toJrtPath(String path) { 275 return toJrtPath(getBytes(path)); 276 } 277 278 private JrtPath toJrtPath(byte[] path) { 279 return new JrtPath(this, path); 280 } 281 282 private Iterator<Path> nodesToIterator(Path path, String childPrefix, List<Node> childNodes) { 283 Function<Node, Path> f = childPrefix == null 284 ? child -> toJrtPath(child.getNameString()) 285 : child -> toJrtPath(childPrefix + child.getNameString().substring(1)); 286 return childNodes.stream().map(f).collect(toList()).iterator(); 287 } 288 289 private List<Node> rootChildren; 290 291 private synchronized void initRootChildren(byte[] path) { 292 if (rootChildren == null) { 293 rootChildren = new ArrayList<>(); 294 rootChildren.addAll(bootImage.findNode(path).getChildren()); 295 } 296 } 297 298 private Iterator<Path> rootDirIterator(byte[] path, String childPrefix) throws IOException { 299 initRootChildren(path); 300 return nodesToIterator(rootPath, childPrefix, rootChildren); 301 } 302 303 private List<Node> modulesChildren; 304 305 private synchronized void initModulesChildren(byte[] path) { 306 if (modulesChildren == null) { 307 modulesChildren = new ArrayList<>(); 308 modulesChildren.addAll(bootImage.findNode(path).getChildren()); 309 } 310 } 311 312 private Iterator<Path> modulesDirIterator(byte[] path, String childPrefix) throws IOException { 313 initModulesChildren(path); 314 return nodesToIterator(new JrtPath(this, path), childPrefix, modulesChildren); 315 } 316 317 private List<Node> packagesChildren; 318 319 private synchronized void initPackagesChildren(byte[] path) { 320 if (packagesChildren == null) { 321 packagesChildren = new ArrayList<>(); 322 packagesChildren.addAll(bootImage.findNode(path).getChildren()); 323 } 324 } 325 326 private Iterator<Path> packagesDirIterator(byte[] path, String childPrefix) throws IOException { 327 initPackagesChildren(path); 328 return nodesToIterator(new JrtPath(this, path), childPrefix, packagesChildren); 329 } 330 } | 141 } catch (NoSuchFileException exp) { 142 return false; 143 } 144 return true; 145 } 146 147 @Override 148 boolean isDirectory(byte[] path, boolean resolveLinks) 149 throws IOException { 150 NodeAndImage ni = checkNode(path); 151 return resolveLinks && ni.node.isLink() 152 ? ni.node.resolveLink(true).isDirectory() 153 : ni.node.isDirectory(); 154 } 155 156 @Override 157 Iterator<Path> iteratorOf(byte[] path, String childPrefix) 158 throws IOException { 159 NodeAndImage ni = checkNode(path); 160 Node node = ni.node.resolveLink(true); 161 if (!node.isDirectory()) { 162 throw new NotDirectoryException(getString(path)); 163 } 164 165 if (node.isRootDir()) { 166 return rootDirIterator(path, childPrefix); 167 } else if (node.isModulesDir()) { 168 return modulesDirIterator(path, childPrefix); 169 } else if (node.isPackagesDir()) { 170 return packagesDirIterator(path, childPrefix); 171 } 172 173 return nodesToIterator(toJrtPath(path), ni.symLink, childPrefix, node.getChildren()); 174 } 175 176 @Override 177 byte[] getFileContent(byte[] path) throws IOException { 178 final NodeAndImage ni = checkResource(path); 179 return ni.getResource(); 180 } 181 182 // Implementation details below this point 183 // clean up this file system - called from finalize and close 184 private void cleanup() throws IOException { 185 if (!isOpen) { 186 return; 187 } 188 189 synchronized (this) { 190 isOpen = false; 191 192 // close all image reader and null out 193 bootImage.close(); 194 bootImage = null; 195 } 196 } 197 198 private static class NodeAndImage { 199 200 final Node node; 201 final ImageReader image; 202 // was there a symlink somewhere while resolving this Node from name? 203 final boolean symLink; 204 205 NodeAndImage(Node node, ImageReader image, boolean symLink) { 206 this.node = node; 207 this.image = image; 208 this.symLink = symLink; 209 } 210 211 byte[] getResource() throws IOException { 212 return image.getResource(node); 213 } 214 } 215 216 private NodeAndImage lookup(byte[] path) { 217 return lookup(path, false); 218 } 219 220 private NodeAndImage lookup(byte[] path, boolean symLink) { 221 ImageReader image = bootImage; 222 Node node; 223 try { 224 node = bootImage.findNode(path); 225 } catch (RuntimeException re) { 226 throw new InvalidPathException(getString(path), re.toString()); 227 } 228 return node != null ? new NodeAndImage(node, image, symLink) : null; 229 } 230 231 private NodeAndImage lookupSymbolic(byte[] path) { 232 for (int i = 1; i < path.length; i++) { 233 if (path[i] == (byte) '/') { 234 byte[] prefix = Arrays.copyOfRange(path, 0, i); 235 NodeAndImage ni = lookup(prefix, true); 236 if (ni == null) { 237 break; 238 } 239 240 if (ni.node.isLink()) { 241 Node link = ni.node.resolveLink(true); 242 // resolved symbolic path concatenated to the rest of the path 243 UTF8String resPath = link.getName().concat(new UTF8String(path, i)); 244 byte[] resPathBytes = resPath.getBytesCopy(); 245 ni = lookup(resPathBytes, true); 246 return ni != null ? ni : lookupSymbolic(resPathBytes); 247 } 248 } 249 } 250 251 return null; 252 } 253 254 private NodeAndImage findNode(byte[] path) throws IOException { 255 NodeAndImage ni = lookup(path); 256 if (ni == null) { 257 ni = lookupSymbolic(path); 258 if (ni == null) { 259 throw new NoSuchFileException(getString(path)); 260 } 261 } 262 return ni; 263 } 264 265 private NodeAndImage checkNode(byte[] path) throws IOException { 268 } 269 270 private NodeAndImage checkResource(byte[] path) throws IOException { 271 NodeAndImage ni = checkNode(path); 272 if (ni.node.isDirectory()) { 273 throw new FileSystemException(getString(path) + " is a directory"); 274 } 275 276 assert ni.node.isResource() : "resource node expected here"; 277 return ni; 278 } 279 280 private JrtPath toJrtPath(String path) { 281 return toJrtPath(getBytes(path)); 282 } 283 284 private JrtPath toJrtPath(byte[] path) { 285 return new JrtPath(this, path); 286 } 287 288 private static final int MODULES_LEN = "/modules/".length(); 289 private static final int PACKAGES_LEN = "/packages/".length(); 290 291 private Iterator<Path> nodesToIterator(Path path, boolean symLink, String childPrefix, List<Node> childNodes) { 292 // Function that maps name -> Path (adding prefix if needed) 293 Function<String, Path> prefixHandler = childPrefix == null 294 ? childStr -> toJrtPath(childStr) 295 : childStr -> toJrtPath(childPrefix + childStr.substring(1)); 296 297 // function to map Node->name 298 Function<Node, String> nodeHandler; 299 if (symLink) { 300 // There was a symlink in the parent dir! We need to make sure that the child paths 301 // use the appropriate parent prefix in the name. 302 String parentStr = path.toAbsolutePath().toString(); 303 // "/packages/java.lang/java.base/java/" -> "/packages/java.lang/" 304 String parentPrefix = parentStr.substring(0, 1 + parentStr.indexOf('/', PACKAGES_LEN)); 305 306 nodeHandler = node -> parentPrefix + node.getNameString().substring(MODULES_LEN); 307 } else { 308 nodeHandler = Node::getNameString; 309 } 310 311 return childNodes.stream().map(nodeHandler.andThen(prefixHandler)).collect(toList()).iterator(); 312 } 313 314 private List<Node> rootChildren; 315 316 private synchronized void initRootChildren(byte[] path) { 317 if (rootChildren == null) { 318 rootChildren = new ArrayList<>(); 319 rootChildren.addAll(bootImage.findNode(path).getChildren()); 320 } 321 } 322 323 private Iterator<Path> rootDirIterator(byte[] path, String childPrefix) throws IOException { 324 initRootChildren(path); 325 return nodesToIterator(rootPath, false, childPrefix, rootChildren); 326 } 327 328 private List<Node> modulesChildren; 329 330 private synchronized void initModulesChildren(byte[] path) { 331 if (modulesChildren == null) { 332 modulesChildren = new ArrayList<>(); 333 modulesChildren.addAll(bootImage.findNode(path).getChildren()); 334 } 335 } 336 337 private Iterator<Path> modulesDirIterator(byte[] path, String childPrefix) throws IOException { 338 initModulesChildren(path); 339 return nodesToIterator(new JrtPath(this, path), false, childPrefix, modulesChildren); 340 } 341 342 private List<Node> packagesChildren; 343 344 private synchronized void initPackagesChildren(byte[] path) { 345 if (packagesChildren == null) { 346 packagesChildren = new ArrayList<>(); 347 packagesChildren.addAll(bootImage.findNode(path).getChildren()); 348 } 349 } 350 351 private Iterator<Path> packagesDirIterator(byte[] path, String childPrefix) throws IOException { 352 initPackagesChildren(path); 353 return nodesToIterator(new JrtPath(this, path), false, childPrefix, packagesChildren); 354 } 355 } |