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