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