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