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