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