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