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 */ 018 package org.apache.hadoop.fs.viewfs; 019 020 import static org.apache.hadoop.fs.viewfs.Constants.PERMISSION_555; 021 022 import java.io.FileNotFoundException; 023 import java.io.IOException; 024 import java.net.URI; 025 import java.net.URISyntaxException; 026 import java.util.Arrays; 027 import java.util.EnumSet; 028 import java.util.HashSet; 029 import java.util.List; 030 import java.util.Map; 031 import java.util.Set; 032 import java.util.Map.Entry; 033 034 import org.apache.hadoop.classification.InterfaceAudience; 035 import org.apache.hadoop.classification.InterfaceStability; 036 import org.apache.hadoop.conf.Configuration; 037 import org.apache.hadoop.fs.BlockLocation; 038 import org.apache.hadoop.fs.ContentSummary; 039 import org.apache.hadoop.fs.CreateFlag; 040 import org.apache.hadoop.fs.FSDataInputStream; 041 import org.apache.hadoop.fs.FSDataOutputStream; 042 import org.apache.hadoop.fs.FileAlreadyExistsException; 043 import org.apache.hadoop.fs.FileChecksum; 044 import org.apache.hadoop.fs.FileStatus; 045 import org.apache.hadoop.fs.FileSystem; 046 import org.apache.hadoop.fs.FsConstants; 047 import org.apache.hadoop.fs.FsServerDefaults; 048 import org.apache.hadoop.fs.Path; 049 import org.apache.hadoop.fs.UnsupportedFileSystemException; 050 import org.apache.hadoop.fs.XAttrSetFlag; 051 import org.apache.hadoop.fs.permission.AclEntry; 052 import org.apache.hadoop.fs.permission.AclStatus; 053 import org.apache.hadoop.fs.permission.AclUtil; 054 import org.apache.hadoop.fs.permission.FsAction; 055 import org.apache.hadoop.fs.permission.FsPermission; 056 import org.apache.hadoop.fs.viewfs.InodeTree.INode; 057 import org.apache.hadoop.fs.viewfs.InodeTree.INodeLink; 058 import org.apache.hadoop.security.AccessControlException; 059 import org.apache.hadoop.security.UserGroupInformation; 060 import org.apache.hadoop.util.Progressable; 061 import 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 */ 070 public 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 void setOwner(final Path f, final String username, 452 final String groupname) throws AccessControlException, 453 FileNotFoundException, 454 IOException { 455 InodeTree.ResolveResult<FileSystem> res = 456 fsState.resolve(getUriPath(f), true); 457 res.targetFileSystem.setOwner(res.remainingPath, username, groupname); 458 } 459 460 @Override 461 public void setPermission(final Path f, final FsPermission permission) 462 throws AccessControlException, FileNotFoundException, 463 IOException { 464 InodeTree.ResolveResult<FileSystem> res = 465 fsState.resolve(getUriPath(f), true); 466 res.targetFileSystem.setPermission(res.remainingPath, permission); 467 } 468 469 @Override 470 public boolean setReplication(final Path f, final short replication) 471 throws AccessControlException, FileNotFoundException, 472 IOException { 473 InodeTree.ResolveResult<FileSystem> res = 474 fsState.resolve(getUriPath(f), true); 475 return res.targetFileSystem.setReplication(res.remainingPath, replication); 476 } 477 478 @Override 479 public void setTimes(final Path f, final long mtime, final long atime) 480 throws AccessControlException, FileNotFoundException, 481 IOException { 482 InodeTree.ResolveResult<FileSystem> res = 483 fsState.resolve(getUriPath(f), true); 484 res.targetFileSystem.setTimes(res.remainingPath, mtime, atime); 485 } 486 487 @Override 488 public void modifyAclEntries(Path path, List<AclEntry> aclSpec) 489 throws IOException { 490 InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(path), 491 true); 492 res.targetFileSystem.modifyAclEntries(res.remainingPath, aclSpec); 493 } 494 495 @Override 496 public void removeAclEntries(Path path, List<AclEntry> aclSpec) 497 throws IOException { 498 InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(path), 499 true); 500 res.targetFileSystem.removeAclEntries(res.remainingPath, aclSpec); 501 } 502 503 @Override 504 public void removeDefaultAcl(Path path) 505 throws IOException { 506 InodeTree.ResolveResult<FileSystem> res = 507 fsState.resolve(getUriPath(path), true); 508 res.targetFileSystem.removeDefaultAcl(res.remainingPath); 509 } 510 511 @Override 512 public void removeAcl(Path path) 513 throws IOException { 514 InodeTree.ResolveResult<FileSystem> res = 515 fsState.resolve(getUriPath(path), true); 516 res.targetFileSystem.removeAcl(res.remainingPath); 517 } 518 519 @Override 520 public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException { 521 InodeTree.ResolveResult<FileSystem> res = 522 fsState.resolve(getUriPath(path), true); 523 res.targetFileSystem.setAcl(res.remainingPath, aclSpec); 524 } 525 526 @Override 527 public AclStatus getAclStatus(Path path) throws IOException { 528 InodeTree.ResolveResult<FileSystem> res = 529 fsState.resolve(getUriPath(path), true); 530 return res.targetFileSystem.getAclStatus(res.remainingPath); 531 } 532 533 @Override 534 public void setXAttr(Path path, String name, byte[] value, 535 EnumSet<XAttrSetFlag> flag) throws IOException { 536 InodeTree.ResolveResult<FileSystem> res = 537 fsState.resolve(getUriPath(path), true); 538 res.targetFileSystem.setXAttr(res.remainingPath, name, value, flag); 539 } 540 541 @Override 542 public byte[] getXAttr(Path path, String name) throws IOException { 543 InodeTree.ResolveResult<FileSystem> res = 544 fsState.resolve(getUriPath(path), true); 545 return res.targetFileSystem.getXAttr(res.remainingPath, name); 546 } 547 548 @Override 549 public Map<String, byte[]> getXAttrs(Path path) throws IOException { 550 InodeTree.ResolveResult<FileSystem> res = 551 fsState.resolve(getUriPath(path), true); 552 return res.targetFileSystem.getXAttrs(res.remainingPath); 553 } 554 555 @Override 556 public Map<String, byte[]> getXAttrs(Path path, List<String> names) 557 throws IOException { 558 InodeTree.ResolveResult<FileSystem> res = 559 fsState.resolve(getUriPath(path), true); 560 return res.targetFileSystem.getXAttrs(res.remainingPath, names); 561 } 562 563 @Override 564 public List<String> listXAttrs(Path path) throws IOException { 565 InodeTree.ResolveResult<FileSystem> res = 566 fsState.resolve(getUriPath(path), true); 567 return res.targetFileSystem.listXAttrs(res.remainingPath); 568 } 569 570 @Override 571 public void removeXAttr(Path path, String name) throws IOException { 572 InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(path), 573 true); 574 res.targetFileSystem.removeXAttr(res.remainingPath, name); 575 } 576 577 @Override 578 public void setVerifyChecksum(final boolean verifyChecksum) { 579 List<InodeTree.MountPoint<FileSystem>> mountPoints = 580 fsState.getMountPoints(); 581 for (InodeTree.MountPoint<FileSystem> mount : mountPoints) { 582 mount.target.targetFileSystem.setVerifyChecksum(verifyChecksum); 583 } 584 } 585 586 @Override 587 public long getDefaultBlockSize() { 588 throw new NotInMountpointException("getDefaultBlockSize"); 589 } 590 591 @Override 592 public short getDefaultReplication() { 593 throw new NotInMountpointException("getDefaultReplication"); 594 } 595 596 @Override 597 public FsServerDefaults getServerDefaults() throws IOException { 598 throw new NotInMountpointException("getServerDefaults"); 599 } 600 601 @Override 602 public long getDefaultBlockSize(Path f) { 603 try { 604 InodeTree.ResolveResult<FileSystem> res = 605 fsState.resolve(getUriPath(f), true); 606 return res.targetFileSystem.getDefaultBlockSize(res.remainingPath); 607 } catch (FileNotFoundException e) { 608 throw new NotInMountpointException(f, "getDefaultBlockSize"); 609 } 610 } 611 612 @Override 613 public short getDefaultReplication(Path f) { 614 try { 615 InodeTree.ResolveResult<FileSystem> res = 616 fsState.resolve(getUriPath(f), true); 617 return res.targetFileSystem.getDefaultReplication(res.remainingPath); 618 } catch (FileNotFoundException e) { 619 throw new NotInMountpointException(f, "getDefaultReplication"); 620 } 621 } 622 623 @Override 624 public FsServerDefaults getServerDefaults(Path f) throws IOException { 625 InodeTree.ResolveResult<FileSystem> res = 626 fsState.resolve(getUriPath(f), true); 627 return res.targetFileSystem.getServerDefaults(res.remainingPath); 628 } 629 630 @Override 631 public ContentSummary getContentSummary(Path f) throws IOException { 632 InodeTree.ResolveResult<FileSystem> res = 633 fsState.resolve(getUriPath(f), true); 634 return res.targetFileSystem.getContentSummary(res.remainingPath); 635 } 636 637 @Override 638 public void setWriteChecksum(final boolean writeChecksum) { 639 List<InodeTree.MountPoint<FileSystem>> mountPoints = 640 fsState.getMountPoints(); 641 for (InodeTree.MountPoint<FileSystem> mount : mountPoints) { 642 mount.target.targetFileSystem.setWriteChecksum(writeChecksum); 643 } 644 } 645 646 @Override 647 public FileSystem[] getChildFileSystems() { 648 List<InodeTree.MountPoint<FileSystem>> mountPoints = 649 fsState.getMountPoints(); 650 Set<FileSystem> children = new HashSet<FileSystem>(); 651 for (InodeTree.MountPoint<FileSystem> mountPoint : mountPoints) { 652 FileSystem targetFs = mountPoint.target.targetFileSystem; 653 children.addAll(Arrays.asList(targetFs.getChildFileSystems())); 654 } 655 return children.toArray(new FileSystem[]{}); 656 } 657 658 public MountPoint[] getMountPoints() { 659 List<InodeTree.MountPoint<FileSystem>> mountPoints = 660 fsState.getMountPoints(); 661 662 MountPoint[] result = new MountPoint[mountPoints.size()]; 663 for ( int i = 0; i < mountPoints.size(); ++i ) { 664 result[i] = new MountPoint(new Path(mountPoints.get(i).src), 665 mountPoints.get(i).target.targetDirLinkList); 666 } 667 return result; 668 } 669 670 /* 671 * An instance of this class represents an internal dir of the viewFs 672 * that is internal dir of the mount table. 673 * It is a read only mount tables and create, mkdir or delete operations 674 * are not allowed. 675 * If called on create or mkdir then this target is the parent of the 676 * directory in which one is trying to create or mkdir; hence 677 * in this case the path name passed in is the last component. 678 * Otherwise this target is the end point of the path and hence 679 * the path name passed in is null. 680 */ 681 static class InternalDirOfViewFs extends FileSystem { 682 final InodeTree.INodeDir<FileSystem> theInternalDir; 683 final long creationTime; // of the the mount table 684 final UserGroupInformation ugi; // the user/group of user who created mtable 685 final URI myUri; 686 687 public InternalDirOfViewFs(final InodeTree.INodeDir<FileSystem> dir, 688 final long cTime, final UserGroupInformation ugi, URI uri) 689 throws URISyntaxException { 690 myUri = uri; 691 try { 692 initialize(myUri, new Configuration()); 693 } catch (IOException e) { 694 throw new RuntimeException("Cannot occur"); 695 } 696 theInternalDir = dir; 697 creationTime = cTime; 698 this.ugi = ugi; 699 } 700 701 static private void checkPathIsSlash(final Path f) throws IOException { 702 if (f != InodeTree.SlashPath) { 703 throw new IOException ( 704 "Internal implementation error: expected file name to be /" ); 705 } 706 } 707 708 @Override 709 public URI getUri() { 710 return myUri; 711 } 712 713 @Override 714 public Path getWorkingDirectory() { 715 throw new RuntimeException ( 716 "Internal impl error: getWorkingDir should not have been called" ); 717 } 718 719 @Override 720 public void setWorkingDirectory(final Path new_dir) { 721 throw new RuntimeException ( 722 "Internal impl error: getWorkingDir should not have been called" ); 723 } 724 725 @Override 726 public FSDataOutputStream append(final Path f, final int bufferSize, 727 final Progressable progress) throws IOException { 728 throw readOnlyMountTable("append", f); 729 } 730 731 @Override 732 public FSDataOutputStream create(final Path f, 733 final FsPermission permission, final boolean overwrite, 734 final int bufferSize, final short replication, final long blockSize, 735 final Progressable progress) throws AccessControlException { 736 throw readOnlyMountTable("create", f); 737 } 738 739 @Override 740 public boolean delete(final Path f, final boolean recursive) 741 throws AccessControlException, IOException { 742 checkPathIsSlash(f); 743 throw readOnlyMountTable("delete", f); 744 } 745 746 @Override 747 @SuppressWarnings("deprecation") 748 public boolean delete(final Path f) 749 throws AccessControlException, IOException { 750 return delete(f, true); 751 } 752 753 @Override 754 public BlockLocation[] getFileBlockLocations(final FileStatus fs, 755 final long start, final long len) throws 756 FileNotFoundException, IOException { 757 checkPathIsSlash(fs.getPath()); 758 throw new FileNotFoundException("Path points to dir not a file"); 759 } 760 761 @Override 762 public FileChecksum getFileChecksum(final Path f) 763 throws FileNotFoundException, IOException { 764 checkPathIsSlash(f); 765 throw new FileNotFoundException("Path points to dir not a file"); 766 } 767 768 @Override 769 public FileStatus getFileStatus(Path f) throws IOException { 770 checkPathIsSlash(f); 771 return new FileStatus(0, true, 0, 0, creationTime, creationTime, 772 PERMISSION_555, ugi.getUserName(), ugi.getGroupNames()[0], 773 774 new Path(theInternalDir.fullPath).makeQualified( 775 myUri, ROOT_PATH)); 776 } 777 778 779 @Override 780 public FileStatus[] listStatus(Path f) throws AccessControlException, 781 FileNotFoundException, IOException { 782 checkPathIsSlash(f); 783 FileStatus[] result = new FileStatus[theInternalDir.children.size()]; 784 int i = 0; 785 for (Entry<String, INode<FileSystem>> iEntry : 786 theInternalDir.children.entrySet()) { 787 INode<FileSystem> inode = iEntry.getValue(); 788 if (inode instanceof INodeLink ) { 789 INodeLink<FileSystem> link = (INodeLink<FileSystem>) inode; 790 791 result[i++] = new FileStatus(0, false, 0, 0, 792 creationTime, creationTime, PERMISSION_555, 793 ugi.getUserName(), ugi.getGroupNames()[0], 794 link.getTargetLink(), 795 new Path(inode.fullPath).makeQualified( 796 myUri, null)); 797 } else { 798 result[i++] = new FileStatus(0, true, 0, 0, 799 creationTime, creationTime, PERMISSION_555, 800 ugi.getUserName(), ugi.getGroupNames()[0], 801 new Path(inode.fullPath).makeQualified( 802 myUri, null)); 803 } 804 } 805 return result; 806 } 807 808 @Override 809 public boolean mkdirs(Path dir, FsPermission permission) 810 throws AccessControlException, FileAlreadyExistsException { 811 if (theInternalDir.isRoot && dir == null) { 812 throw new FileAlreadyExistsException("/ already exits"); 813 } 814 // Note dir starts with / 815 if (theInternalDir.children.containsKey(dir.toString().substring(1))) { 816 return true; // this is the stupid semantics of FileSystem 817 } 818 throw readOnlyMountTable("mkdirs", dir); 819 } 820 821 @Override 822 public FSDataInputStream open(Path f, int bufferSize) 823 throws AccessControlException, FileNotFoundException, IOException { 824 checkPathIsSlash(f); 825 throw new FileNotFoundException("Path points to dir not a file"); 826 } 827 828 @Override 829 public boolean rename(Path src, Path dst) throws AccessControlException, 830 IOException { 831 checkPathIsSlash(src); 832 checkPathIsSlash(dst); 833 throw readOnlyMountTable("rename", src); 834 } 835 836 @Override 837 public void setOwner(Path f, String username, String groupname) 838 throws AccessControlException, IOException { 839 checkPathIsSlash(f); 840 throw readOnlyMountTable("setOwner", f); 841 } 842 843 @Override 844 public void setPermission(Path f, FsPermission permission) 845 throws AccessControlException, IOException { 846 checkPathIsSlash(f); 847 throw readOnlyMountTable("setPermission", f); 848 } 849 850 @Override 851 public boolean setReplication(Path f, short replication) 852 throws AccessControlException, IOException { 853 checkPathIsSlash(f); 854 throw readOnlyMountTable("setReplication", f); 855 } 856 857 @Override 858 public void setTimes(Path f, long mtime, long atime) 859 throws AccessControlException, IOException { 860 checkPathIsSlash(f); 861 throw readOnlyMountTable("setTimes", f); 862 } 863 864 @Override 865 public void setVerifyChecksum(boolean verifyChecksum) { 866 // Noop for viewfs 867 } 868 869 @Override 870 public FsServerDefaults getServerDefaults(Path f) throws IOException { 871 throw new NotInMountpointException(f, "getServerDefaults"); 872 } 873 874 @Override 875 public long getDefaultBlockSize(Path f) { 876 throw new NotInMountpointException(f, "getDefaultBlockSize"); 877 } 878 879 @Override 880 public short getDefaultReplication(Path f) { 881 throw new NotInMountpointException(f, "getDefaultReplication"); 882 } 883 884 @Override 885 public void modifyAclEntries(Path path, List<AclEntry> aclSpec) 886 throws IOException { 887 checkPathIsSlash(path); 888 throw readOnlyMountTable("modifyAclEntries", path); 889 } 890 891 @Override 892 public void removeAclEntries(Path path, List<AclEntry> aclSpec) 893 throws IOException { 894 checkPathIsSlash(path); 895 throw readOnlyMountTable("removeAclEntries", path); 896 } 897 898 @Override 899 public void removeDefaultAcl(Path path) throws IOException { 900 checkPathIsSlash(path); 901 throw readOnlyMountTable("removeDefaultAcl", path); 902 } 903 904 @Override 905 public void removeAcl(Path path) throws IOException { 906 checkPathIsSlash(path); 907 throw readOnlyMountTable("removeAcl", path); 908 } 909 910 @Override 911 public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException { 912 checkPathIsSlash(path); 913 throw readOnlyMountTable("setAcl", path); 914 } 915 916 @Override 917 public AclStatus getAclStatus(Path path) throws IOException { 918 checkPathIsSlash(path); 919 return new AclStatus.Builder().owner(ugi.getUserName()) 920 .group(ugi.getGroupNames()[0]) 921 .addEntries(AclUtil.getMinimalAcl(PERMISSION_555)) 922 .stickyBit(false).build(); 923 } 924 925 @Override 926 public void setXAttr(Path path, String name, byte[] value, 927 EnumSet<XAttrSetFlag> flag) throws IOException { 928 checkPathIsSlash(path); 929 throw readOnlyMountTable("setXAttr", path); 930 } 931 932 @Override 933 public byte[] getXAttr(Path path, String name) throws IOException { 934 throw new NotInMountpointException(path, "getXAttr"); 935 } 936 937 @Override 938 public Map<String, byte[]> getXAttrs(Path path) throws IOException { 939 throw new NotInMountpointException(path, "getXAttrs"); 940 } 941 942 @Override 943 public Map<String, byte[]> getXAttrs(Path path, List<String> names) 944 throws IOException { 945 throw new NotInMountpointException(path, "getXAttrs"); 946 } 947 948 @Override 949 public List<String> listXAttrs(Path path) throws IOException { 950 throw new NotInMountpointException(path, "listXAttrs"); 951 } 952 953 @Override 954 public void removeXAttr(Path path, String name) throws IOException { 955 checkPathIsSlash(path); 956 throw readOnlyMountTable("removeXAttr", path); 957 } 958 } 959 }