001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.fs.viewfs; 019 020import static org.apache.hadoop.fs.viewfs.Constants.PERMISSION_555; 021 022import java.io.FileNotFoundException; 023import java.io.IOException; 024import java.net.URI; 025import java.net.URISyntaxException; 026import java.util.Arrays; 027import java.util.Collection; 028import java.util.EnumSet; 029import java.util.HashSet; 030import java.util.List; 031import java.util.Map; 032import java.util.Set; 033import java.util.Map.Entry; 034 035import org.apache.hadoop.classification.InterfaceAudience; 036import org.apache.hadoop.classification.InterfaceStability; 037import org.apache.hadoop.conf.Configuration; 038import org.apache.hadoop.fs.BlockLocation; 039import org.apache.hadoop.fs.BlockStoragePolicySpi; 040import org.apache.hadoop.fs.ContentSummary; 041import org.apache.hadoop.fs.CreateFlag; 042import org.apache.hadoop.fs.FSDataInputStream; 043import org.apache.hadoop.fs.FSDataOutputStream; 044import org.apache.hadoop.fs.FileAlreadyExistsException; 045import org.apache.hadoop.fs.FileChecksum; 046import org.apache.hadoop.fs.FileStatus; 047import org.apache.hadoop.fs.FileSystem; 048import org.apache.hadoop.fs.FsConstants; 049import org.apache.hadoop.fs.FsServerDefaults; 050import org.apache.hadoop.fs.LocatedFileStatus; 051import org.apache.hadoop.fs.Path; 052import org.apache.hadoop.fs.PathFilter; 053import org.apache.hadoop.fs.QuotaUsage; 054import org.apache.hadoop.fs.RemoteIterator; 055import org.apache.hadoop.fs.UnsupportedFileSystemException; 056import org.apache.hadoop.fs.XAttrSetFlag; 057import org.apache.hadoop.fs.permission.AclEntry; 058import org.apache.hadoop.fs.permission.AclStatus; 059import org.apache.hadoop.fs.permission.AclUtil; 060import org.apache.hadoop.fs.permission.FsAction; 061import org.apache.hadoop.fs.permission.FsPermission; 062import org.apache.hadoop.fs.viewfs.InodeTree.INode; 063import org.apache.hadoop.fs.viewfs.InodeTree.INodeLink; 064import org.apache.hadoop.security.AccessControlException; 065import org.apache.hadoop.security.UserGroupInformation; 066import org.apache.hadoop.util.Progressable; 067import org.apache.hadoop.util.Time; 068 069/** 070 * ViewFileSystem (extends the FileSystem interface) implements a client-side 071 * mount table. Its spec and implementation is identical to {@link ViewFs}. 072 */ 073 074@InterfaceAudience.Public 075@InterfaceStability.Evolving /*Evolving for a release,to be changed to Stable */ 076public class ViewFileSystem extends FileSystem { 077 078 private static final Path ROOT_PATH = new Path(Path.SEPARATOR); 079 080 static AccessControlException readOnlyMountTable(final String operation, 081 final String p) { 082 return new AccessControlException( 083 "InternalDir of ViewFileSystem is readonly; operation=" + operation + 084 "Path=" + p); 085 } 086 static AccessControlException readOnlyMountTable(final String operation, 087 final Path p) { 088 return readOnlyMountTable(operation, p.toString()); 089 } 090 091 static public class MountPoint { 092 private Path src; // the src of the mount 093 private URI[] targets; // target of the mount; Multiple targets imply mergeMount 094 MountPoint(Path srcPath, URI[] targetURIs) { 095 src = srcPath; 096 targets = targetURIs; 097 } 098 Path getSrc() { 099 return src; 100 } 101 URI[] getTargets() { 102 return targets; 103 } 104 } 105 106 final long creationTime; // of the the mount table 107 final UserGroupInformation ugi; // the user/group of user who created mtable 108 URI myUri; 109 private Path workingDir; 110 Configuration config; 111 InodeTree<FileSystem> fsState; // the fs state; ie the mount table 112 Path homeDir = null; 113 114 /** 115 * Make the path Absolute and get the path-part of a pathname. 116 * Checks that URI matches this file system 117 * and that the path-part is a valid name. 118 * 119 * @param p path 120 * @return path-part of the Path p 121 */ 122 private String getUriPath(final Path p) { 123 checkPath(p); 124 return makeAbsolute(p).toUri().getPath(); 125 } 126 127 private Path makeAbsolute(final Path f) { 128 return f.isAbsolute() ? f : new Path(workingDir, f); 129 } 130 131 /** 132 * This is the constructor with the signature needed by 133 * {@link FileSystem#createFileSystem(URI, Configuration)} 134 * 135 * After this constructor is called initialize() is called. 136 * @throws IOException 137 */ 138 public ViewFileSystem() throws IOException { 139 ugi = UserGroupInformation.getCurrentUser(); 140 creationTime = Time.now(); 141 } 142 143 /** 144 * Return the protocol scheme for the FileSystem. 145 * <p/> 146 * 147 * @return <code>viewfs</code> 148 */ 149 @Override 150 public String getScheme() { 151 return "viewfs"; 152 } 153 154 /** 155 * Called after a new FileSystem instance is constructed. 156 * @param theUri a uri whose authority section names the host, port, etc. for 157 * this FileSystem 158 * @param conf the configuration 159 */ 160 @Override 161 public void initialize(final URI theUri, final Configuration conf) 162 throws IOException { 163 super.initialize(theUri, conf); 164 setConf(conf); 165 config = conf; 166 // Now build client side view (i.e. client side mount table) from config. 167 final String authority = theUri.getAuthority(); 168 try { 169 myUri = new URI(FsConstants.VIEWFS_SCHEME, authority, "/", null, null); 170 fsState = new InodeTree<FileSystem>(conf, authority) { 171 172 @Override 173 protected 174 FileSystem getTargetFileSystem(final URI uri) 175 throws URISyntaxException, IOException { 176 return new ChRootedFileSystem(uri, config); 177 } 178 179 @Override 180 protected 181 FileSystem getTargetFileSystem(final INodeDir<FileSystem> dir) 182 throws URISyntaxException { 183 return new InternalDirOfViewFs(dir, creationTime, ugi, myUri); 184 } 185 186 @Override 187 protected 188 FileSystem getTargetFileSystem(URI[] mergeFsURIList) 189 throws URISyntaxException, UnsupportedFileSystemException { 190 throw new UnsupportedFileSystemException("mergefs not implemented"); 191 // return MergeFs.createMergeFs(mergeFsURIList, config); 192 } 193 }; 194 workingDir = this.getHomeDirectory(); 195 } catch (URISyntaxException e) { 196 throw new IOException("URISyntax exception: " + theUri); 197 } 198 199 } 200 201 202 /** 203 * Convenience Constructor for apps to call directly 204 * @param theUri which must be that of ViewFileSystem 205 * @param conf 206 * @throws IOException 207 */ 208 ViewFileSystem(final URI theUri, final Configuration conf) 209 throws IOException { 210 this(); 211 initialize(theUri, conf); 212 } 213 214 /** 215 * Convenience Constructor for apps to call directly 216 * @param conf 217 * @throws IOException 218 */ 219 public ViewFileSystem(final Configuration conf) throws IOException { 220 this(FsConstants.VIEWFS_URI, conf); 221 } 222 223 public Path getTrashCanLocation(final Path f) throws FileNotFoundException { 224 final InodeTree.ResolveResult<FileSystem> res = 225 fsState.resolve(getUriPath(f), true); 226 return res.isInternalDir() ? null : res.targetFileSystem.getHomeDirectory(); 227 } 228 229 @Override 230 public URI getUri() { 231 return myUri; 232 } 233 234 @Override 235 public Path resolvePath(final Path f) 236 throws IOException { 237 final InodeTree.ResolveResult<FileSystem> res; 238 res = fsState.resolve(getUriPath(f), true); 239 if (res.isInternalDir()) { 240 return f; 241 } 242 return res.targetFileSystem.resolvePath(res.remainingPath); 243 } 244 245 @Override 246 public Path getHomeDirectory() { 247 if (homeDir == null) { 248 String base = fsState.getHomeDirPrefixValue(); 249 if (base == null) { 250 base = "/user"; 251 } 252 homeDir = (base.equals("/") ? 253 this.makeQualified(new Path(base + ugi.getShortUserName())): 254 this.makeQualified(new Path(base + "/" + ugi.getShortUserName()))); 255 } 256 return homeDir; 257 } 258 259 @Override 260 public Path getWorkingDirectory() { 261 return workingDir; 262 } 263 264 @Override 265 public void setWorkingDirectory(final Path new_dir) { 266 getUriPath(new_dir); // this validates the path 267 workingDir = makeAbsolute(new_dir); 268 } 269 270 @Override 271 public FSDataOutputStream append(final Path f, final int bufferSize, 272 final Progressable progress) throws IOException { 273 InodeTree.ResolveResult<FileSystem> res = 274 fsState.resolve(getUriPath(f), true); 275 return res.targetFileSystem.append(res.remainingPath, bufferSize, progress); 276 } 277 278 @Override 279 public FSDataOutputStream createNonRecursive(Path f, FsPermission permission, 280 EnumSet<CreateFlag> flags, int bufferSize, short replication, long blockSize, 281 Progressable progress) throws IOException { 282 InodeTree.ResolveResult<FileSystem> res; 283 try { 284 res = fsState.resolve(getUriPath(f), false); 285 } catch (FileNotFoundException e) { 286 throw readOnlyMountTable("create", f); 287 } 288 assert(res.remainingPath != null); 289 return res.targetFileSystem.createNonRecursive(res.remainingPath, permission, 290 flags, bufferSize, replication, blockSize, progress); 291 } 292 293 @Override 294 public FSDataOutputStream create(final Path f, final FsPermission permission, 295 final boolean overwrite, final int bufferSize, final short replication, 296 final long blockSize, final Progressable progress) throws IOException { 297 InodeTree.ResolveResult<FileSystem> res; 298 try { 299 res = fsState.resolve(getUriPath(f), false); 300 } catch (FileNotFoundException e) { 301 throw readOnlyMountTable("create", f); 302 } 303 assert(res.remainingPath != null); 304 return res.targetFileSystem.create(res.remainingPath, permission, 305 overwrite, bufferSize, replication, blockSize, progress); 306 } 307 308 309 @Override 310 public boolean delete(final Path f, final boolean recursive) 311 throws AccessControlException, FileNotFoundException, 312 IOException { 313 InodeTree.ResolveResult<FileSystem> res = 314 fsState.resolve(getUriPath(f), true); 315 // If internal dir or target is a mount link (ie remainingPath is Slash) 316 if (res.isInternalDir() || res.remainingPath == InodeTree.SlashPath) { 317 throw readOnlyMountTable("delete", f); 318 } 319 return res.targetFileSystem.delete(res.remainingPath, recursive); 320 } 321 322 @Override 323 @SuppressWarnings("deprecation") 324 public boolean delete(final Path f) 325 throws AccessControlException, FileNotFoundException, 326 IOException { 327 return delete(f, true); 328 } 329 330 @Override 331 public BlockLocation[] getFileBlockLocations(FileStatus fs, 332 long start, long len) throws IOException { 333 final InodeTree.ResolveResult<FileSystem> res = 334 fsState.resolve(getUriPath(fs.getPath()), true); 335 return res.targetFileSystem.getFileBlockLocations( 336 new ViewFsFileStatus(fs, res.remainingPath), start, len); 337 } 338 339 @Override 340 public FileChecksum getFileChecksum(final Path f) 341 throws AccessControlException, FileNotFoundException, 342 IOException { 343 InodeTree.ResolveResult<FileSystem> res = 344 fsState.resolve(getUriPath(f), true); 345 return res.targetFileSystem.getFileChecksum(res.remainingPath); 346 } 347 348 349 private static FileStatus fixFileStatus(FileStatus orig, 350 Path qualified) throws IOException { 351 // FileStatus#getPath is a fully qualified path relative to the root of 352 // target file system. 353 // We need to change it to viewfs URI - relative to root of mount table. 354 355 // The implementors of RawLocalFileSystem were trying to be very smart. 356 // They implement FileStatus#getOwner lazily -- the object 357 // returned is really a RawLocalFileSystem that expect the 358 // FileStatus#getPath to be unchanged so that it can get owner when needed. 359 // Hence we need to interpose a new ViewFileSystemFileStatus that 360 // works around. 361 if ("file".equals(orig.getPath().toUri().getScheme())) { 362 orig = wrapLocalFileStatus(orig, qualified); 363 } 364 365 orig.setPath(qualified); 366 return orig; 367 } 368 369 private static FileStatus wrapLocalFileStatus(FileStatus orig, 370 Path qualified) { 371 return orig instanceof LocatedFileStatus 372 ? new ViewFsLocatedFileStatus((LocatedFileStatus)orig, qualified) 373 : new ViewFsFileStatus(orig, qualified); 374 } 375 376 377 @Override 378 public FileStatus getFileStatus(final Path f) throws AccessControlException, 379 FileNotFoundException, IOException { 380 InodeTree.ResolveResult<FileSystem> res = 381 fsState.resolve(getUriPath(f), true); 382 FileStatus status = res.targetFileSystem.getFileStatus(res.remainingPath); 383 return fixFileStatus(status, this.makeQualified(f)); 384 } 385 386 @Override 387 public void access(Path path, FsAction mode) throws AccessControlException, 388 FileNotFoundException, IOException { 389 InodeTree.ResolveResult<FileSystem> res = 390 fsState.resolve(getUriPath(path), true); 391 res.targetFileSystem.access(res.remainingPath, mode); 392 } 393 394 @Override 395 public FileStatus[] listStatus(final Path f) throws AccessControlException, 396 FileNotFoundException, IOException { 397 InodeTree.ResolveResult<FileSystem> res = 398 fsState.resolve(getUriPath(f), true); 399 400 FileStatus[] statusLst = res.targetFileSystem.listStatus(res.remainingPath); 401 if (!res.isInternalDir()) { 402 // We need to change the name in the FileStatus as described in 403 // {@link #getFileStatus } 404 int i = 0; 405 for (FileStatus status : statusLst) { 406 statusLst[i++] = fixFileStatus(status, 407 getChrootedPath(res, status, f)); 408 } 409 } 410 return statusLst; 411 } 412 413 @Override 414 public RemoteIterator<LocatedFileStatus>listLocatedStatus(final Path f, 415 final PathFilter filter) throws FileNotFoundException, IOException { 416 final InodeTree.ResolveResult<FileSystem> res = fsState 417 .resolve(getUriPath(f), true); 418 final RemoteIterator<LocatedFileStatus> statusIter = res.targetFileSystem 419 .listLocatedStatus(res.remainingPath); 420 421 if (res.isInternalDir()) { 422 return statusIter; 423 } 424 425 return new RemoteIterator<LocatedFileStatus>() { 426 @Override 427 public boolean hasNext() throws IOException { 428 return statusIter.hasNext(); 429 } 430 431 @Override 432 public LocatedFileStatus next() throws IOException { 433 final LocatedFileStatus status = statusIter.next(); 434 return (LocatedFileStatus)fixFileStatus(status, 435 getChrootedPath(res, status, f)); 436 } 437 }; 438 } 439 440 private Path getChrootedPath(InodeTree.ResolveResult<FileSystem> res, 441 FileStatus status, Path f) throws IOException { 442 final String suffix = ((ChRootedFileSystem)res.targetFileSystem) 443 .stripOutRoot(status.getPath()); 444 return this.makeQualified( 445 suffix.length() == 0 ? f : new Path(res.resolvedPath, suffix)); 446 } 447 448 @Override 449 public boolean mkdirs(final Path dir, final FsPermission permission) 450 throws IOException { 451 InodeTree.ResolveResult<FileSystem> res = 452 fsState.resolve(getUriPath(dir), false); 453 return res.targetFileSystem.mkdirs(res.remainingPath, permission); 454 } 455 456 @Override 457 public FSDataInputStream open(final Path f, final int bufferSize) 458 throws AccessControlException, FileNotFoundException, 459 IOException { 460 InodeTree.ResolveResult<FileSystem> res = 461 fsState.resolve(getUriPath(f), true); 462 return res.targetFileSystem.open(res.remainingPath, bufferSize); 463 } 464 465 466 @Override 467 public boolean rename(final Path src, final Path dst) throws IOException { 468 // passing resolveLastComponet as false to catch renaming a mount point to 469 // itself. We need to catch this as an internal operation and fail. 470 InodeTree.ResolveResult<FileSystem> resSrc = 471 fsState.resolve(getUriPath(src), false); 472 473 if (resSrc.isInternalDir()) { 474 throw readOnlyMountTable("rename", src); 475 } 476 477 InodeTree.ResolveResult<FileSystem> resDst = 478 fsState.resolve(getUriPath(dst), false); 479 if (resDst.isInternalDir()) { 480 throw readOnlyMountTable("rename", dst); 481 } 482 /** 483 // Alternate 1: renames within same file system - valid but we disallow 484 // Alternate 2: (as described in next para - valid but we have disallowed it 485 // 486 // Note we compare the URIs. the URIs include the link targets. 487 // hence we allow renames across mount links as long as the mount links 488 // point to the same target. 489 if (!resSrc.targetFileSystem.getUri().equals( 490 resDst.targetFileSystem.getUri())) { 491 throw new IOException("Renames across Mount points not supported"); 492 } 493 */ 494 495 // 496 // Alternate 3 : renames ONLY within the the same mount links. 497 // 498 if (resSrc.targetFileSystem !=resDst.targetFileSystem) { 499 throw new IOException("Renames across Mount points not supported"); 500 } 501 return resSrc.targetFileSystem.rename(resSrc.remainingPath, 502 resDst.remainingPath); 503 } 504 505 @Override 506 public boolean truncate(final Path f, final long newLength) 507 throws IOException { 508 InodeTree.ResolveResult<FileSystem> res = 509 fsState.resolve(getUriPath(f), true); 510 return res.targetFileSystem.truncate(f, newLength); 511 } 512 513 @Override 514 public void setOwner(final Path f, final String username, 515 final String groupname) throws AccessControlException, 516 FileNotFoundException, 517 IOException { 518 InodeTree.ResolveResult<FileSystem> res = 519 fsState.resolve(getUriPath(f), true); 520 res.targetFileSystem.setOwner(res.remainingPath, username, groupname); 521 } 522 523 @Override 524 public void setPermission(final Path f, final FsPermission permission) 525 throws AccessControlException, FileNotFoundException, 526 IOException { 527 InodeTree.ResolveResult<FileSystem> res = 528 fsState.resolve(getUriPath(f), true); 529 res.targetFileSystem.setPermission(res.remainingPath, permission); 530 } 531 532 @Override 533 public boolean setReplication(final Path f, final short replication) 534 throws AccessControlException, FileNotFoundException, 535 IOException { 536 InodeTree.ResolveResult<FileSystem> res = 537 fsState.resolve(getUriPath(f), true); 538 return res.targetFileSystem.setReplication(res.remainingPath, replication); 539 } 540 541 @Override 542 public void setTimes(final Path f, final long mtime, final long atime) 543 throws AccessControlException, FileNotFoundException, 544 IOException { 545 InodeTree.ResolveResult<FileSystem> res = 546 fsState.resolve(getUriPath(f), true); 547 res.targetFileSystem.setTimes(res.remainingPath, mtime, atime); 548 } 549 550 @Override 551 public void modifyAclEntries(Path path, List<AclEntry> aclSpec) 552 throws IOException { 553 InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(path), 554 true); 555 res.targetFileSystem.modifyAclEntries(res.remainingPath, aclSpec); 556 } 557 558 @Override 559 public void removeAclEntries(Path path, List<AclEntry> aclSpec) 560 throws IOException { 561 InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(path), 562 true); 563 res.targetFileSystem.removeAclEntries(res.remainingPath, aclSpec); 564 } 565 566 @Override 567 public void removeDefaultAcl(Path path) 568 throws IOException { 569 InodeTree.ResolveResult<FileSystem> res = 570 fsState.resolve(getUriPath(path), true); 571 res.targetFileSystem.removeDefaultAcl(res.remainingPath); 572 } 573 574 @Override 575 public void removeAcl(Path path) 576 throws IOException { 577 InodeTree.ResolveResult<FileSystem> res = 578 fsState.resolve(getUriPath(path), true); 579 res.targetFileSystem.removeAcl(res.remainingPath); 580 } 581 582 @Override 583 public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException { 584 InodeTree.ResolveResult<FileSystem> res = 585 fsState.resolve(getUriPath(path), true); 586 res.targetFileSystem.setAcl(res.remainingPath, aclSpec); 587 } 588 589 @Override 590 public AclStatus getAclStatus(Path path) throws IOException { 591 InodeTree.ResolveResult<FileSystem> res = 592 fsState.resolve(getUriPath(path), true); 593 return res.targetFileSystem.getAclStatus(res.remainingPath); 594 } 595 596 @Override 597 public void setXAttr(Path path, String name, byte[] value, 598 EnumSet<XAttrSetFlag> flag) throws IOException { 599 InodeTree.ResolveResult<FileSystem> res = 600 fsState.resolve(getUriPath(path), true); 601 res.targetFileSystem.setXAttr(res.remainingPath, name, value, flag); 602 } 603 604 @Override 605 public byte[] getXAttr(Path path, String name) throws IOException { 606 InodeTree.ResolveResult<FileSystem> res = 607 fsState.resolve(getUriPath(path), true); 608 return res.targetFileSystem.getXAttr(res.remainingPath, name); 609 } 610 611 @Override 612 public Map<String, byte[]> getXAttrs(Path path) throws IOException { 613 InodeTree.ResolveResult<FileSystem> res = 614 fsState.resolve(getUriPath(path), true); 615 return res.targetFileSystem.getXAttrs(res.remainingPath); 616 } 617 618 @Override 619 public Map<String, byte[]> getXAttrs(Path path, List<String> names) 620 throws IOException { 621 InodeTree.ResolveResult<FileSystem> res = 622 fsState.resolve(getUriPath(path), true); 623 return res.targetFileSystem.getXAttrs(res.remainingPath, names); 624 } 625 626 @Override 627 public List<String> listXAttrs(Path path) throws IOException { 628 InodeTree.ResolveResult<FileSystem> res = 629 fsState.resolve(getUriPath(path), true); 630 return res.targetFileSystem.listXAttrs(res.remainingPath); 631 } 632 633 @Override 634 public void removeXAttr(Path path, String name) throws IOException { 635 InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(path), 636 true); 637 res.targetFileSystem.removeXAttr(res.remainingPath, name); 638 } 639 640 @Override 641 public void setVerifyChecksum(final boolean verifyChecksum) { 642 List<InodeTree.MountPoint<FileSystem>> mountPoints = 643 fsState.getMountPoints(); 644 for (InodeTree.MountPoint<FileSystem> mount : mountPoints) { 645 mount.target.targetFileSystem.setVerifyChecksum(verifyChecksum); 646 } 647 } 648 649 @Override 650 public long getDefaultBlockSize() { 651 throw new NotInMountpointException("getDefaultBlockSize"); 652 } 653 654 @Override 655 public short getDefaultReplication() { 656 throw new NotInMountpointException("getDefaultReplication"); 657 } 658 659 @Override 660 public FsServerDefaults getServerDefaults() throws IOException { 661 throw new NotInMountpointException("getServerDefaults"); 662 } 663 664 @Override 665 public long getDefaultBlockSize(Path f) { 666 try { 667 InodeTree.ResolveResult<FileSystem> res = 668 fsState.resolve(getUriPath(f), true); 669 return res.targetFileSystem.getDefaultBlockSize(res.remainingPath); 670 } catch (FileNotFoundException e) { 671 throw new NotInMountpointException(f, "getDefaultBlockSize"); 672 } 673 } 674 675 @Override 676 public short getDefaultReplication(Path f) { 677 try { 678 InodeTree.ResolveResult<FileSystem> res = 679 fsState.resolve(getUriPath(f), true); 680 return res.targetFileSystem.getDefaultReplication(res.remainingPath); 681 } catch (FileNotFoundException e) { 682 throw new NotInMountpointException(f, "getDefaultReplication"); 683 } 684 } 685 686 @Override 687 public FsServerDefaults getServerDefaults(Path f) throws IOException { 688 InodeTree.ResolveResult<FileSystem> res = 689 fsState.resolve(getUriPath(f), true); 690 return res.targetFileSystem.getServerDefaults(res.remainingPath); 691 } 692 693 @Override 694 public ContentSummary getContentSummary(Path f) throws IOException { 695 InodeTree.ResolveResult<FileSystem> res = 696 fsState.resolve(getUriPath(f), true); 697 return res.targetFileSystem.getContentSummary(res.remainingPath); 698 } 699 700 @Override 701 public QuotaUsage getQuotaUsage(Path f) throws IOException { 702 InodeTree.ResolveResult<FileSystem> res = 703 fsState.resolve(getUriPath(f), true); 704 return res.targetFileSystem.getQuotaUsage(res.remainingPath); 705 } 706 707 @Override 708 public void setWriteChecksum(final boolean writeChecksum) { 709 List<InodeTree.MountPoint<FileSystem>> mountPoints = 710 fsState.getMountPoints(); 711 for (InodeTree.MountPoint<FileSystem> mount : mountPoints) { 712 mount.target.targetFileSystem.setWriteChecksum(writeChecksum); 713 } 714 } 715 716 @Override 717 public FileSystem[] getChildFileSystems() { 718 List<InodeTree.MountPoint<FileSystem>> mountPoints = 719 fsState.getMountPoints(); 720 Set<FileSystem> children = new HashSet<FileSystem>(); 721 for (InodeTree.MountPoint<FileSystem> mountPoint : mountPoints) { 722 FileSystem targetFs = mountPoint.target.targetFileSystem; 723 children.addAll(Arrays.asList(targetFs.getChildFileSystems())); 724 } 725 return children.toArray(new FileSystem[]{}); 726 } 727 728 public MountPoint[] getMountPoints() { 729 List<InodeTree.MountPoint<FileSystem>> mountPoints = 730 fsState.getMountPoints(); 731 732 MountPoint[] result = new MountPoint[mountPoints.size()]; 733 for ( int i = 0; i < mountPoints.size(); ++i ) { 734 result[i] = new MountPoint(new Path(mountPoints.get(i).src), 735 mountPoints.get(i).target.targetDirLinkList); 736 } 737 return result; 738 } 739 740 @Override 741 public Path createSnapshot(Path path, String snapshotName) 742 throws IOException { 743 InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(path), 744 true); 745 return res.targetFileSystem.createSnapshot(res.remainingPath, snapshotName); 746 } 747 748 @Override 749 public void renameSnapshot(Path path, String snapshotOldName, 750 String snapshotNewName) throws IOException { 751 InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(path), 752 true); 753 res.targetFileSystem.renameSnapshot(res.remainingPath, snapshotOldName, 754 snapshotNewName); 755 } 756 757 @Override 758 public void deleteSnapshot(Path path, String snapshotName) 759 throws IOException { 760 InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(path), 761 true); 762 res.targetFileSystem.deleteSnapshot(res.remainingPath, snapshotName); 763 } 764 765 @Override 766 public void setStoragePolicy(Path src, String policyName) throws IOException { 767 InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(src), 768 true); 769 res.targetFileSystem.setStoragePolicy(res.remainingPath, policyName); 770 } 771 772 @Override 773 public void unsetStoragePolicy(Path src) throws IOException { 774 InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(src), 775 true); 776 res.targetFileSystem.unsetStoragePolicy(res.remainingPath); 777 } 778 779 @Override 780 public BlockStoragePolicySpi getStoragePolicy(Path src) throws IOException { 781 InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(src), 782 true); 783 return res.targetFileSystem.getStoragePolicy(res.remainingPath); 784 } 785 786 @Override 787 public Collection<? extends BlockStoragePolicySpi> getAllStoragePolicies() 788 throws IOException { 789 Collection<BlockStoragePolicySpi> allPolicies = new HashSet<>(); 790 for (FileSystem fs : getChildFileSystems()) { 791 try { 792 Collection<? extends BlockStoragePolicySpi> policies = 793 fs.getAllStoragePolicies(); 794 allPolicies.addAll(policies); 795 } catch (UnsupportedOperationException e) { 796 // ignored 797 } 798 } 799 return allPolicies; 800 } 801 802 /* 803 * An instance of this class represents an internal dir of the viewFs 804 * that is internal dir of the mount table. 805 * It is a read only mount tables and create, mkdir or delete operations 806 * are not allowed. 807 * If called on create or mkdir then this target is the parent of the 808 * directory in which one is trying to create or mkdir; hence 809 * in this case the path name passed in is the last component. 810 * Otherwise this target is the end point of the path and hence 811 * the path name passed in is null. 812 */ 813 static class InternalDirOfViewFs extends FileSystem { 814 final InodeTree.INodeDir<FileSystem> theInternalDir; 815 final long creationTime; // of the the mount table 816 final UserGroupInformation ugi; // the user/group of user who created mtable 817 final URI myUri; 818 819 public InternalDirOfViewFs(final InodeTree.INodeDir<FileSystem> dir, 820 final long cTime, final UserGroupInformation ugi, URI uri) 821 throws URISyntaxException { 822 myUri = uri; 823 try { 824 initialize(myUri, new Configuration()); 825 } catch (IOException e) { 826 throw new RuntimeException("Cannot occur"); 827 } 828 theInternalDir = dir; 829 creationTime = cTime; 830 this.ugi = ugi; 831 } 832 833 static private void checkPathIsSlash(final Path f) throws IOException { 834 if (f != InodeTree.SlashPath) { 835 throw new IOException ( 836 "Internal implementation error: expected file name to be /" ); 837 } 838 } 839 840 @Override 841 public URI getUri() { 842 return myUri; 843 } 844 845 @Override 846 public Path getWorkingDirectory() { 847 throw new RuntimeException ( 848 "Internal impl error: getWorkingDir should not have been called" ); 849 } 850 851 @Override 852 public void setWorkingDirectory(final Path new_dir) { 853 throw new RuntimeException ( 854 "Internal impl error: getWorkingDir should not have been called" ); 855 } 856 857 @Override 858 public FSDataOutputStream append(final Path f, final int bufferSize, 859 final Progressable progress) throws IOException { 860 throw readOnlyMountTable("append", f); 861 } 862 863 @Override 864 public FSDataOutputStream create(final Path f, 865 final FsPermission permission, final boolean overwrite, 866 final int bufferSize, final short replication, final long blockSize, 867 final Progressable progress) throws AccessControlException { 868 throw readOnlyMountTable("create", f); 869 } 870 871 @Override 872 public boolean delete(final Path f, final boolean recursive) 873 throws AccessControlException, IOException { 874 checkPathIsSlash(f); 875 throw readOnlyMountTable("delete", f); 876 } 877 878 @Override 879 @SuppressWarnings("deprecation") 880 public boolean delete(final Path f) 881 throws AccessControlException, IOException { 882 return delete(f, true); 883 } 884 885 @Override 886 public BlockLocation[] getFileBlockLocations(final FileStatus fs, 887 final long start, final long len) throws 888 FileNotFoundException, IOException { 889 checkPathIsSlash(fs.getPath()); 890 throw new FileNotFoundException("Path points to dir not a file"); 891 } 892 893 @Override 894 public FileChecksum getFileChecksum(final Path f) 895 throws FileNotFoundException, IOException { 896 checkPathIsSlash(f); 897 throw new FileNotFoundException("Path points to dir not a file"); 898 } 899 900 @Override 901 public FileStatus getFileStatus(Path f) throws IOException { 902 checkPathIsSlash(f); 903 return new FileStatus(0, true, 0, 0, creationTime, creationTime, 904 PERMISSION_555, ugi.getUserName(), ugi.getPrimaryGroupName(), 905 906 new Path(theInternalDir.fullPath).makeQualified( 907 myUri, ROOT_PATH)); 908 } 909 910 911 @Override 912 public FileStatus[] listStatus(Path f) throws AccessControlException, 913 FileNotFoundException, IOException { 914 checkPathIsSlash(f); 915 FileStatus[] result = new FileStatus[theInternalDir.children.size()]; 916 int i = 0; 917 for (Entry<String, INode<FileSystem>> iEntry : 918 theInternalDir.children.entrySet()) { 919 INode<FileSystem> inode = iEntry.getValue(); 920 if (inode instanceof INodeLink ) { 921 INodeLink<FileSystem> link = (INodeLink<FileSystem>) inode; 922 923 result[i++] = new FileStatus(0, false, 0, 0, 924 creationTime, creationTime, PERMISSION_555, 925 ugi.getUserName(), ugi.getPrimaryGroupName(), 926 link.getTargetLink(), 927 new Path(inode.fullPath).makeQualified( 928 myUri, null)); 929 } else { 930 result[i++] = new FileStatus(0, true, 0, 0, 931 creationTime, creationTime, PERMISSION_555, 932 ugi.getUserName(), ugi.getGroupNames()[0], 933 new Path(inode.fullPath).makeQualified( 934 myUri, null)); 935 } 936 } 937 return result; 938 } 939 940 @Override 941 public boolean mkdirs(Path dir, FsPermission permission) 942 throws AccessControlException, FileAlreadyExistsException { 943 if (theInternalDir.isRoot && dir == null) { 944 throw new FileAlreadyExistsException("/ already exits"); 945 } 946 // Note dir starts with / 947 if (theInternalDir.children.containsKey(dir.toString().substring(1))) { 948 return true; // this is the stupid semantics of FileSystem 949 } 950 throw readOnlyMountTable("mkdirs", dir); 951 } 952 953 @Override 954 public FSDataInputStream open(Path f, int bufferSize) 955 throws AccessControlException, FileNotFoundException, IOException { 956 checkPathIsSlash(f); 957 throw new FileNotFoundException("Path points to dir not a file"); 958 } 959 960 @Override 961 public boolean rename(Path src, Path dst) throws AccessControlException, 962 IOException { 963 checkPathIsSlash(src); 964 checkPathIsSlash(dst); 965 throw readOnlyMountTable("rename", src); 966 } 967 968 @Override 969 public boolean truncate(Path f, long newLength) throws IOException { 970 throw readOnlyMountTable("truncate", f); 971 } 972 973 @Override 974 public void setOwner(Path f, String username, String groupname) 975 throws AccessControlException, IOException { 976 checkPathIsSlash(f); 977 throw readOnlyMountTable("setOwner", f); 978 } 979 980 @Override 981 public void setPermission(Path f, FsPermission permission) 982 throws AccessControlException, IOException { 983 checkPathIsSlash(f); 984 throw readOnlyMountTable("setPermission", f); 985 } 986 987 @Override 988 public boolean setReplication(Path f, short replication) 989 throws AccessControlException, IOException { 990 checkPathIsSlash(f); 991 throw readOnlyMountTable("setReplication", f); 992 } 993 994 @Override 995 public void setTimes(Path f, long mtime, long atime) 996 throws AccessControlException, IOException { 997 checkPathIsSlash(f); 998 throw readOnlyMountTable("setTimes", f); 999 } 1000 1001 @Override 1002 public void setVerifyChecksum(boolean verifyChecksum) { 1003 // Noop for viewfs 1004 } 1005 1006 @Override 1007 public FsServerDefaults getServerDefaults(Path f) throws IOException { 1008 throw new NotInMountpointException(f, "getServerDefaults"); 1009 } 1010 1011 @Override 1012 public long getDefaultBlockSize(Path f) { 1013 throw new NotInMountpointException(f, "getDefaultBlockSize"); 1014 } 1015 1016 @Override 1017 public short getDefaultReplication(Path f) { 1018 throw new NotInMountpointException(f, "getDefaultReplication"); 1019 } 1020 1021 @Override 1022 public void modifyAclEntries(Path path, List<AclEntry> aclSpec) 1023 throws IOException { 1024 checkPathIsSlash(path); 1025 throw readOnlyMountTable("modifyAclEntries", path); 1026 } 1027 1028 @Override 1029 public void removeAclEntries(Path path, List<AclEntry> aclSpec) 1030 throws IOException { 1031 checkPathIsSlash(path); 1032 throw readOnlyMountTable("removeAclEntries", path); 1033 } 1034 1035 @Override 1036 public void removeDefaultAcl(Path path) throws IOException { 1037 checkPathIsSlash(path); 1038 throw readOnlyMountTable("removeDefaultAcl", path); 1039 } 1040 1041 @Override 1042 public void removeAcl(Path path) throws IOException { 1043 checkPathIsSlash(path); 1044 throw readOnlyMountTable("removeAcl", path); 1045 } 1046 1047 @Override 1048 public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException { 1049 checkPathIsSlash(path); 1050 throw readOnlyMountTable("setAcl", path); 1051 } 1052 1053 @Override 1054 public AclStatus getAclStatus(Path path) throws IOException { 1055 checkPathIsSlash(path); 1056 return new AclStatus.Builder().owner(ugi.getUserName()) 1057 .group(ugi.getPrimaryGroupName()) 1058 .addEntries(AclUtil.getMinimalAcl(PERMISSION_555)) 1059 .stickyBit(false).build(); 1060 } 1061 1062 @Override 1063 public void setXAttr(Path path, String name, byte[] value, 1064 EnumSet<XAttrSetFlag> flag) throws IOException { 1065 checkPathIsSlash(path); 1066 throw readOnlyMountTable("setXAttr", path); 1067 } 1068 1069 @Override 1070 public byte[] getXAttr(Path path, String name) throws IOException { 1071 throw new NotInMountpointException(path, "getXAttr"); 1072 } 1073 1074 @Override 1075 public Map<String, byte[]> getXAttrs(Path path) throws IOException { 1076 throw new NotInMountpointException(path, "getXAttrs"); 1077 } 1078 1079 @Override 1080 public Map<String, byte[]> getXAttrs(Path path, List<String> names) 1081 throws IOException { 1082 throw new NotInMountpointException(path, "getXAttrs"); 1083 } 1084 1085 @Override 1086 public List<String> listXAttrs(Path path) throws IOException { 1087 throw new NotInMountpointException(path, "listXAttrs"); 1088 } 1089 1090 @Override 1091 public void removeXAttr(Path path, String name) throws IOException { 1092 checkPathIsSlash(path); 1093 throw readOnlyMountTable("removeXAttr", path); 1094 } 1095 1096 @Override 1097 public Path createSnapshot(Path path, String snapshotName) 1098 throws IOException { 1099 checkPathIsSlash(path); 1100 throw readOnlyMountTable("createSnapshot", path); 1101 } 1102 1103 @Override 1104 public void renameSnapshot(Path path, String snapshotOldName, 1105 String snapshotNewName) throws IOException { 1106 checkPathIsSlash(path); 1107 throw readOnlyMountTable("renameSnapshot", path); 1108 } 1109 1110 @Override 1111 public void deleteSnapshot(Path path, String snapshotName) 1112 throws IOException { 1113 checkPathIsSlash(path); 1114 throw readOnlyMountTable("deleteSnapshot", path); 1115 } 1116 1117 @Override 1118 public QuotaUsage getQuotaUsage(Path f) throws IOException { 1119 throw new NotInMountpointException(f, "getQuotaUsage"); 1120 } 1121 1122 @Override 1123 public void setStoragePolicy(Path src, String policyName) 1124 throws IOException { 1125 checkPathIsSlash(src); 1126 throw readOnlyMountTable("setStoragePolicy", src); 1127 } 1128 1129 @Override 1130 public void unsetStoragePolicy(Path src) throws IOException { 1131 checkPathIsSlash(src); 1132 throw readOnlyMountTable("unsetStoragePolicy", src); 1133 } 1134 1135 @Override 1136 public BlockStoragePolicySpi getStoragePolicy(Path src) throws IOException { 1137 throw new NotInMountpointException(src, "getStoragePolicy"); 1138 } 1139 1140 @Override 1141 public Collection<? extends BlockStoragePolicySpi> getAllStoragePolicies() 1142 throws IOException { 1143 Collection<BlockStoragePolicySpi> allPolicies = new HashSet<>(); 1144 for (FileSystem fs : getChildFileSystems()) { 1145 try { 1146 Collection<? extends BlockStoragePolicySpi> policies = 1147 fs.getAllStoragePolicies(); 1148 allPolicies.addAll(policies); 1149 } catch (UnsupportedOperationException e) { 1150 // ignored 1151 } 1152 } 1153 return allPolicies; 1154 } 1155 } 1156}