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