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_555; 021 022import java.io.FileNotFoundException; 023import java.io.IOException; 024import java.net.URI; 025import java.net.URISyntaxException; 026import java.util.ArrayList; 027import java.util.EnumSet; 028import java.util.List; 029import java.util.Map; 030import java.util.Map.Entry; 031 032import org.apache.hadoop.classification.InterfaceAudience; 033import org.apache.hadoop.classification.InterfaceStability; 034import org.apache.hadoop.conf.Configuration; 035import org.apache.hadoop.fs.AbstractFileSystem; 036import org.apache.hadoop.fs.BlockLocation; 037import org.apache.hadoop.fs.CreateFlag; 038import org.apache.hadoop.fs.FSDataInputStream; 039import org.apache.hadoop.fs.FSDataOutputStream; 040import org.apache.hadoop.fs.FileAlreadyExistsException; 041import org.apache.hadoop.fs.FileChecksum; 042import org.apache.hadoop.fs.FileStatus; 043import org.apache.hadoop.fs.FsConstants; 044import org.apache.hadoop.fs.FsServerDefaults; 045import org.apache.hadoop.fs.FsStatus; 046import org.apache.hadoop.fs.Options.ChecksumOpt; 047import org.apache.hadoop.fs.ParentNotDirectoryException; 048import org.apache.hadoop.fs.Path; 049import org.apache.hadoop.fs.RemoteIterator; 050import org.apache.hadoop.fs.UnresolvedLinkException; 051import org.apache.hadoop.fs.UnsupportedFileSystemException; 052import org.apache.hadoop.fs.XAttrSetFlag; 053import org.apache.hadoop.fs.local.LocalConfigKeys; 054import org.apache.hadoop.fs.permission.AclEntry; 055import org.apache.hadoop.fs.permission.AclUtil; 056import org.apache.hadoop.fs.permission.AclStatus; 057import org.apache.hadoop.fs.permission.FsAction; 058import org.apache.hadoop.fs.permission.FsPermission; 059import org.apache.hadoop.fs.viewfs.InodeTree.INode; 060import org.apache.hadoop.fs.viewfs.InodeTree.INodeLink; 061import org.apache.hadoop.security.AccessControlException; 062import org.apache.hadoop.security.UserGroupInformation; 063import org.apache.hadoop.security.token.Token; 064import org.apache.hadoop.util.Progressable; 065import org.apache.hadoop.util.Time; 066 067 068/** 069 * ViewFs (extends the AbstractFileSystem interface) implements a client-side 070 * mount table. The viewFs file system is implemented completely in memory on 071 * the client side. The client-side mount table allows a client to provide a 072 * customized view of a file system namespace that is composed from 073 * one or more individual file systems (a localFs or Hdfs, S3fs, etc). 074 * For example one could have a mount table that provides links such as 075 * <ul> 076 * <li> /user -> hdfs://nnContainingUserDir/user 077 * <li> /project/foo -> hdfs://nnProject1/projects/foo 078 * <li> /project/bar -> hdfs://nnProject2/projects/bar 079 * <li> /tmp -> hdfs://nnTmp/privateTmpForUserXXX 080 * </ul> 081 * 082 * ViewFs is specified with the following URI: <b>viewfs:///</b> 083 * <p> 084 * To use viewfs one would typically set the default file system in the 085 * config (i.e. fs.default.name< = viewfs:///) along with the 086 * mount table config variables as described below. 087 * 088 * <p> 089 * <b> ** Config variables to specify the mount table entries ** </b> 090 * <p> 091 * 092 * The file system is initialized from the standard Hadoop config through 093 * config variables. 094 * See {@link FsConstants} for URI and Scheme constants; 095 * See {@link Constants} for config var constants; 096 * see {@link ConfigUtil} for convenient lib. 097 * 098 * <p> 099 * All the mount table config entries for view fs are prefixed by 100 * <b>fs.viewfs.mounttable.</b> 101 * For example the above example can be specified with the following 102 * config variables: 103 * <ul> 104 * <li> fs.viewfs.mounttable.default.link./user= 105 * hdfs://nnContainingUserDir/user 106 * <li> fs.viewfs.mounttable.default.link./project/foo= 107 * hdfs://nnProject1/projects/foo 108 * <li> fs.viewfs.mounttable.default.link./project/bar= 109 * hdfs://nnProject2/projects/bar 110 * <li> fs.viewfs.mounttable.default.link./tmp= 111 * hdfs://nnTmp/privateTmpForUserXXX 112 * </ul> 113 * 114 * The default mount table (when no authority is specified) is 115 * from config variables prefixed by <b>fs.viewFs.mounttable.default </b> 116 * The authority component of a URI can be used to specify a different mount 117 * table. For example, 118 * <ul> 119 * <li> viewfs://sanjayMountable/ 120 * </ul> 121 * is initialized from fs.viewFs.mounttable.sanjayMountable.* config variables. 122 * 123 * <p> 124 * <b> **** Merge Mounts **** </b>(NOTE: merge mounts are not implemented yet.) 125 * <p> 126 * 127 * One can also use "MergeMounts" to merge several directories (this is 128 * sometimes called union-mounts or junction-mounts in the literature. 129 * For example of the home directories are stored on say two file systems 130 * (because they do not fit on one) then one could specify a mount 131 * entry such as following merges two dirs: 132 * <ul> 133 * <li> /user -> hdfs://nnUser1/user,hdfs://nnUser2/user 134 * </ul> 135 * Such a mergeLink can be specified with the following config var where "," 136 * is used as the separator for each of links to be merged: 137 * <ul> 138 * <li> fs.viewfs.mounttable.default.linkMerge./user= 139 * hdfs://nnUser1/user,hdfs://nnUser1/user 140 * </ul> 141 * A special case of the merge mount is where mount table's root is merged 142 * with the root (slash) of another file system: 143 * <ul> 144 * <li> fs.viewfs.mounttable.default.linkMergeSlash=hdfs://nn99/ 145 * </ul> 146 * In this cases the root of the mount table is merged with the root of 147 * <b>hdfs://nn99/ </b> 148 */ 149 150@InterfaceAudience.Public 151@InterfaceStability.Evolving /*Evolving for a release,to be changed to Stable */ 152public class ViewFs extends AbstractFileSystem { 153 final long creationTime; // of the the mount table 154 final UserGroupInformation ugi; // the user/group of user who created mtable 155 final Configuration config; 156 InodeTree<AbstractFileSystem> fsState; // the fs state; ie the mount table 157 Path homeDir = null; 158 159 static AccessControlException readOnlyMountTable(final String operation, 160 final String p) { 161 return new AccessControlException( 162 "InternalDir of ViewFileSystem is readonly; operation=" + operation + 163 "Path=" + p); 164 } 165 static AccessControlException readOnlyMountTable(final String operation, 166 final Path p) { 167 return readOnlyMountTable(operation, p.toString()); 168 } 169 170 171 static public class MountPoint { 172 private Path src; // the src of the mount 173 private URI[] targets; // target of the mount; Multiple targets imply mergeMount 174 MountPoint(Path srcPath, URI[] targetURIs) { 175 src = srcPath; 176 targets = targetURIs; 177 } 178 Path getSrc() { 179 return src; 180 } 181 URI[] getTargets() { 182 return targets; 183 } 184 } 185 186 public ViewFs(final Configuration conf) throws IOException, 187 URISyntaxException { 188 this(FsConstants.VIEWFS_URI, conf); 189 } 190 191 /** 192 * This constructor has the signature needed by 193 * {@link AbstractFileSystem#createFileSystem(URI, Configuration)}. 194 * 195 * @param theUri which must be that of ViewFs 196 * @param conf 197 * @throws IOException 198 * @throws URISyntaxException 199 */ 200 ViewFs(final URI theUri, final Configuration conf) throws IOException, 201 URISyntaxException { 202 super(theUri, FsConstants.VIEWFS_SCHEME, false, -1); 203 creationTime = Time.now(); 204 ugi = UserGroupInformation.getCurrentUser(); 205 config = conf; 206 // Now build client side view (i.e. client side mount table) from config. 207 String authority = theUri.getAuthority(); 208 fsState = new InodeTree<AbstractFileSystem>(conf, authority) { 209 210 @Override 211 protected 212 AbstractFileSystem getTargetFileSystem(final URI uri) 213 throws URISyntaxException, UnsupportedFileSystemException { 214 String pathString = uri.getPath(); 215 if (pathString.isEmpty()) { 216 pathString = "/"; 217 } 218 return new ChRootedFs( 219 AbstractFileSystem.createFileSystem(uri, config), 220 new Path(pathString)); 221 } 222 223 @Override 224 protected 225 AbstractFileSystem getTargetFileSystem( 226 final INodeDir<AbstractFileSystem> dir) throws URISyntaxException { 227 return new InternalDirOfViewFs(dir, creationTime, ugi, getUri()); 228 } 229 230 @Override 231 protected 232 AbstractFileSystem getTargetFileSystem(URI[] mergeFsURIList) 233 throws URISyntaxException, UnsupportedFileSystemException { 234 throw new UnsupportedFileSystemException("mergefs not implemented yet"); 235 // return MergeFs.createMergeFs(mergeFsURIList, config); 236 } 237 }; 238 } 239 240 @Override 241 public FsServerDefaults getServerDefaults() throws IOException { 242 return LocalConfigKeys.getServerDefaults(); 243 } 244 245 @Override 246 public int getUriDefaultPort() { 247 return -1; 248 } 249 250 @Override 251 public Path getHomeDirectory() { 252 if (homeDir == null) { 253 String base = fsState.getHomeDirPrefixValue(); 254 if (base == null) { 255 base = "/user"; 256 } 257 homeDir = (base.equals("/") ? 258 this.makeQualified(new Path(base + ugi.getShortUserName())): 259 this.makeQualified(new Path(base + "/" + ugi.getShortUserName()))); 260 } 261 return homeDir; 262 } 263 264 @Override 265 public Path resolvePath(final Path f) throws FileNotFoundException, 266 AccessControlException, UnresolvedLinkException, IOException { 267 final InodeTree.ResolveResult<AbstractFileSystem> res; 268 res = fsState.resolve(getUriPath(f), true); 269 if (res.isInternalDir()) { 270 return f; 271 } 272 return res.targetFileSystem.resolvePath(res.remainingPath); 273 274 } 275 276 @Override 277 public FSDataOutputStream createInternal(final Path f, 278 final EnumSet<CreateFlag> flag, final FsPermission absolutePermission, 279 final int bufferSize, final short replication, final long blockSize, 280 final Progressable progress, final ChecksumOpt checksumOpt, 281 final boolean createParent) throws AccessControlException, 282 FileAlreadyExistsException, FileNotFoundException, 283 ParentNotDirectoryException, UnsupportedFileSystemException, 284 UnresolvedLinkException, IOException { 285 InodeTree.ResolveResult<AbstractFileSystem> res; 286 try { 287 res = fsState.resolve(getUriPath(f), false); 288 } catch (FileNotFoundException e) { 289 if (createParent) { 290 throw readOnlyMountTable("create", f); 291 } else { 292 throw e; 293 } 294 } 295 assert(res.remainingPath != null); 296 return res.targetFileSystem.createInternal(res.remainingPath, flag, 297 absolutePermission, bufferSize, replication, 298 blockSize, progress, checksumOpt, 299 createParent); 300 } 301 302 @Override 303 public boolean delete(final Path f, final boolean recursive) 304 throws AccessControlException, FileNotFoundException, 305 UnresolvedLinkException, IOException { 306 InodeTree.ResolveResult<AbstractFileSystem> res = 307 fsState.resolve(getUriPath(f), true); 308 // If internal dir or target is a mount link (ie remainingPath is Slash) 309 if (res.isInternalDir() || res.remainingPath == InodeTree.SlashPath) { 310 throw new AccessControlException( 311 "Cannot delete internal mount table directory: " + f); 312 } 313 return res.targetFileSystem.delete(res.remainingPath, recursive); 314 } 315 316 @Override 317 public BlockLocation[] getFileBlockLocations(final Path f, final long start, 318 final long len) throws AccessControlException, FileNotFoundException, 319 UnresolvedLinkException, IOException { 320 InodeTree.ResolveResult<AbstractFileSystem> res = 321 fsState.resolve(getUriPath(f), true); 322 return 323 res.targetFileSystem.getFileBlockLocations(res.remainingPath, start, len); 324 } 325 326 @Override 327 public FileChecksum getFileChecksum(final Path f) 328 throws AccessControlException, FileNotFoundException, 329 UnresolvedLinkException, IOException { 330 InodeTree.ResolveResult<AbstractFileSystem> res = 331 fsState.resolve(getUriPath(f), true); 332 return res.targetFileSystem.getFileChecksum(res.remainingPath); 333 } 334 335 @Override 336 public FileStatus getFileStatus(final Path f) throws AccessControlException, 337 FileNotFoundException, UnresolvedLinkException, IOException { 338 InodeTree.ResolveResult<AbstractFileSystem> res = 339 fsState.resolve(getUriPath(f), true); 340 341 // FileStatus#getPath is a fully qualified path relative to the root of 342 // target file system. 343 // We need to change it to viewfs URI - relative to root of mount table. 344 345 // The implementors of RawLocalFileSystem were trying to be very smart. 346 // They implement FileStatus#getOwener lazily -- the object 347 // returned is really a RawLocalFileSystem that expect the 348 // FileStatus#getPath to be unchanged so that it can get owner when needed. 349 // Hence we need to interpose a new ViewFsFileStatus that works around. 350 351 352 FileStatus status = res.targetFileSystem.getFileStatus(res.remainingPath); 353 return new ViewFsFileStatus(status, this.makeQualified(f)); 354 } 355 356 @Override 357 public void access(Path path, FsAction mode) throws AccessControlException, 358 FileNotFoundException, UnresolvedLinkException, IOException { 359 InodeTree.ResolveResult<AbstractFileSystem> res = 360 fsState.resolve(getUriPath(path), true); 361 res.targetFileSystem.access(res.remainingPath, mode); 362 } 363 364 @Override 365 public FileStatus getFileLinkStatus(final Path f) 366 throws AccessControlException, FileNotFoundException, 367 UnsupportedFileSystemException, IOException { 368 InodeTree.ResolveResult<AbstractFileSystem> res = 369 fsState.resolve(getUriPath(f), false); // do not follow mount link 370 return res.targetFileSystem.getFileLinkStatus(res.remainingPath); 371 } 372 373 @Override 374 public FsStatus getFsStatus() throws AccessControlException, 375 FileNotFoundException, IOException { 376 return new FsStatus(0, 0, 0); 377 } 378 379 @Override 380 public RemoteIterator<FileStatus> listStatusIterator(final Path f) 381 throws AccessControlException, FileNotFoundException, 382 UnresolvedLinkException, IOException { 383 final InodeTree.ResolveResult<AbstractFileSystem> res = 384 fsState.resolve(getUriPath(f), true); 385 final RemoteIterator<FileStatus> fsIter = 386 res.targetFileSystem.listStatusIterator(res.remainingPath); 387 if (res.isInternalDir()) { 388 return fsIter; 389 } 390 391 return new RemoteIterator<FileStatus>() { 392 final RemoteIterator<FileStatus> myIter; 393 final ChRootedFs targetFs; 394 { // Init 395 myIter = fsIter; 396 targetFs = (ChRootedFs) res.targetFileSystem; 397 } 398 399 @Override 400 public boolean hasNext() throws IOException { 401 return myIter.hasNext(); 402 } 403 404 @Override 405 public FileStatus next() throws IOException { 406 FileStatus status = myIter.next(); 407 String suffix = targetFs.stripOutRoot(status.getPath()); 408 return new ViewFsFileStatus(status, makeQualified( 409 suffix.length() == 0 ? f : new Path(res.resolvedPath, suffix))); 410 } 411 }; 412 } 413 414 @Override 415 public FileStatus[] listStatus(final Path f) throws AccessControlException, 416 FileNotFoundException, UnresolvedLinkException, IOException { 417 InodeTree.ResolveResult<AbstractFileSystem> res = 418 fsState.resolve(getUriPath(f), true); 419 420 FileStatus[] statusLst = res.targetFileSystem.listStatus(res.remainingPath); 421 if (!res.isInternalDir()) { 422 // We need to change the name in the FileStatus as described in 423 // {@link #getFileStatus } 424 ChRootedFs targetFs; 425 targetFs = (ChRootedFs) res.targetFileSystem; 426 int i = 0; 427 for (FileStatus status : statusLst) { 428 String suffix = targetFs.stripOutRoot(status.getPath()); 429 statusLst[i++] = new ViewFsFileStatus(status, this.makeQualified( 430 suffix.length() == 0 ? f : new Path(res.resolvedPath, suffix))); 431 } 432 } 433 return statusLst; 434 } 435 436 @Override 437 public void mkdir(final Path dir, final FsPermission permission, 438 final boolean createParent) throws AccessControlException, 439 FileAlreadyExistsException, 440 FileNotFoundException, UnresolvedLinkException, IOException { 441 InodeTree.ResolveResult<AbstractFileSystem> res = 442 fsState.resolve(getUriPath(dir), false); 443 res.targetFileSystem.mkdir(res.remainingPath, permission, createParent); 444 } 445 446 @Override 447 public FSDataInputStream open(final Path f, final int bufferSize) 448 throws AccessControlException, FileNotFoundException, 449 UnresolvedLinkException, IOException { 450 InodeTree.ResolveResult<AbstractFileSystem> res = 451 fsState.resolve(getUriPath(f), true); 452 return res.targetFileSystem.open(res.remainingPath, bufferSize); 453 } 454 455 @Override 456 public boolean truncate(final Path f, final long newLength) 457 throws AccessControlException, FileNotFoundException, 458 UnresolvedLinkException, IOException { 459 InodeTree.ResolveResult<AbstractFileSystem> res = 460 fsState.resolve(getUriPath(f), true); 461 return res.targetFileSystem.truncate(res.remainingPath, newLength); 462 } 463 464 @Override 465 public void renameInternal(final Path src, final Path dst, 466 final boolean overwrite) throws IOException, UnresolvedLinkException { 467 // passing resolveLastComponet as false to catch renaming a mount point 468 // itself we need to catch this as an internal operation and fail. 469 InodeTree.ResolveResult<AbstractFileSystem> resSrc = 470 fsState.resolve(getUriPath(src), false); 471 472 if (resSrc.isInternalDir()) { 473 throw new AccessControlException( 474 "Cannot Rename within internal dirs of mount table: it is readOnly"); 475 } 476 477 InodeTree.ResolveResult<AbstractFileSystem> resDst = 478 fsState.resolve(getUriPath(dst), false); 479 if (resDst.isInternalDir()) { 480 throw new AccessControlException( 481 "Cannot Rename within internal dirs of mount table: it is readOnly"); 482 } 483 484 /** 485 // Alternate 1: renames within same file system - valid but we disallow 486 // Alternate 2: (as described in next para - valid but we have disallowed it 487 // 488 // Note we compare the URIs. the URIs include the link targets. 489 // hence we allow renames across mount links as long as the mount links 490 // point to the same target. 491 if (!resSrc.targetFileSystem.getUri().equals( 492 resDst.targetFileSystem.getUri())) { 493 throw new IOException("Renames across Mount points not supported"); 494 } 495 */ 496 497 // 498 // Alternate 3 : renames ONLY within the the same mount links. 499 // 500 501 if (resSrc.targetFileSystem !=resDst.targetFileSystem) { 502 throw new IOException("Renames across Mount points not supported"); 503 } 504 505 resSrc.targetFileSystem.renameInternal(resSrc.remainingPath, 506 resDst.remainingPath, overwrite); 507 } 508 509 @Override 510 public void renameInternal(final Path src, final Path dst) 511 throws AccessControlException, FileAlreadyExistsException, 512 FileNotFoundException, ParentNotDirectoryException, 513 UnresolvedLinkException, IOException { 514 renameInternal(src, dst, false); 515 } 516 517 @Override 518 public boolean supportsSymlinks() { 519 return true; 520 } 521 522 @Override 523 public void createSymlink(final Path target, final Path link, 524 final boolean createParent) throws IOException, UnresolvedLinkException { 525 InodeTree.ResolveResult<AbstractFileSystem> res; 526 try { 527 res = fsState.resolve(getUriPath(link), false); 528 } catch (FileNotFoundException e) { 529 if (createParent) { 530 throw readOnlyMountTable("createSymlink", link); 531 } else { 532 throw e; 533 } 534 } 535 assert(res.remainingPath != null); 536 res.targetFileSystem.createSymlink(target, res.remainingPath, 537 createParent); 538 } 539 540 @Override 541 public Path getLinkTarget(final Path f) throws IOException { 542 InodeTree.ResolveResult<AbstractFileSystem> res = 543 fsState.resolve(getUriPath(f), false); // do not follow mount link 544 return res.targetFileSystem.getLinkTarget(res.remainingPath); 545 } 546 547 @Override 548 public void setOwner(final Path f, final String username, 549 final String groupname) throws AccessControlException, 550 FileNotFoundException, UnresolvedLinkException, IOException { 551 InodeTree.ResolveResult<AbstractFileSystem> res = 552 fsState.resolve(getUriPath(f), true); 553 res.targetFileSystem.setOwner(res.remainingPath, username, groupname); 554 } 555 556 @Override 557 public void setPermission(final Path f, final FsPermission permission) 558 throws AccessControlException, FileNotFoundException, 559 UnresolvedLinkException, IOException { 560 InodeTree.ResolveResult<AbstractFileSystem> res = 561 fsState.resolve(getUriPath(f), true); 562 res.targetFileSystem.setPermission(res.remainingPath, permission); 563 564 } 565 566 @Override 567 public boolean setReplication(final Path f, final short replication) 568 throws AccessControlException, FileNotFoundException, 569 UnresolvedLinkException, IOException { 570 InodeTree.ResolveResult<AbstractFileSystem> res = 571 fsState.resolve(getUriPath(f), true); 572 return res.targetFileSystem.setReplication(res.remainingPath, replication); 573 } 574 575 @Override 576 public void setTimes(final Path f, final long mtime, final long atime) 577 throws AccessControlException, FileNotFoundException, 578 UnresolvedLinkException, IOException { 579 InodeTree.ResolveResult<AbstractFileSystem> res = 580 fsState.resolve(getUriPath(f), true); 581 res.targetFileSystem.setTimes(res.remainingPath, mtime, atime); 582 } 583 584 @Override 585 public void setVerifyChecksum(final boolean verifyChecksum) 586 throws AccessControlException, IOException { 587 // This is a file system level operations, however ViewFs 588 // points to many file systems. Noop for ViewFs. 589 } 590 591 public MountPoint[] getMountPoints() { 592 List<InodeTree.MountPoint<AbstractFileSystem>> mountPoints = 593 fsState.getMountPoints(); 594 595 MountPoint[] result = new MountPoint[mountPoints.size()]; 596 for ( int i = 0; i < mountPoints.size(); ++i ) { 597 result[i] = new MountPoint(new Path(mountPoints.get(i).src), 598 mountPoints.get(i).target.targetDirLinkList); 599 } 600 return result; 601 } 602 603 @Override 604 public List<Token<?>> getDelegationTokens(String renewer) throws IOException { 605 List<InodeTree.MountPoint<AbstractFileSystem>> mountPoints = 606 fsState.getMountPoints(); 607 int initialListSize = 0; 608 for (InodeTree.MountPoint<AbstractFileSystem> im : mountPoints) { 609 initialListSize += im.target.targetDirLinkList.length; 610 } 611 List<Token<?>> result = new ArrayList<Token<?>>(initialListSize); 612 for ( int i = 0; i < mountPoints.size(); ++i ) { 613 List<Token<?>> tokens = 614 mountPoints.get(i).target.targetFileSystem.getDelegationTokens(renewer); 615 if (tokens != null) { 616 result.addAll(tokens); 617 } 618 } 619 return result; 620 } 621 622 @Override 623 public boolean isValidName(String src) { 624 // Prefix validated at mount time and rest of path validated by mount target. 625 return true; 626 } 627 628 @Override 629 public void modifyAclEntries(Path path, List<AclEntry> aclSpec) 630 throws IOException { 631 InodeTree.ResolveResult<AbstractFileSystem> res = 632 fsState.resolve(getUriPath(path), true); 633 res.targetFileSystem.modifyAclEntries(res.remainingPath, aclSpec); 634 } 635 636 @Override 637 public void removeAclEntries(Path path, List<AclEntry> aclSpec) 638 throws IOException { 639 InodeTree.ResolveResult<AbstractFileSystem> res = 640 fsState.resolve(getUriPath(path), true); 641 res.targetFileSystem.removeAclEntries(res.remainingPath, aclSpec); 642 } 643 644 @Override 645 public void removeDefaultAcl(Path path) 646 throws IOException { 647 InodeTree.ResolveResult<AbstractFileSystem> res = 648 fsState.resolve(getUriPath(path), true); 649 res.targetFileSystem.removeDefaultAcl(res.remainingPath); 650 } 651 652 @Override 653 public void removeAcl(Path path) 654 throws IOException { 655 InodeTree.ResolveResult<AbstractFileSystem> res = 656 fsState.resolve(getUriPath(path), true); 657 res.targetFileSystem.removeAcl(res.remainingPath); 658 } 659 660 @Override 661 public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException { 662 InodeTree.ResolveResult<AbstractFileSystem> res = 663 fsState.resolve(getUriPath(path), true); 664 res.targetFileSystem.setAcl(res.remainingPath, aclSpec); 665 } 666 667 @Override 668 public AclStatus getAclStatus(Path path) throws IOException { 669 InodeTree.ResolveResult<AbstractFileSystem> res = 670 fsState.resolve(getUriPath(path), true); 671 return res.targetFileSystem.getAclStatus(res.remainingPath); 672 } 673 674 @Override 675 public void setXAttr(Path path, String name, byte[] value, 676 EnumSet<XAttrSetFlag> flag) throws IOException { 677 InodeTree.ResolveResult<AbstractFileSystem> res = 678 fsState.resolve(getUriPath(path), true); 679 res.targetFileSystem.setXAttr(res.remainingPath, name, value, flag); 680 } 681 682 @Override 683 public byte[] getXAttr(Path path, String name) throws IOException { 684 InodeTree.ResolveResult<AbstractFileSystem> res = 685 fsState.resolve(getUriPath(path), true); 686 return res.targetFileSystem.getXAttr(res.remainingPath, name); 687 } 688 689 @Override 690 public Map<String, byte[]> getXAttrs(Path path) throws IOException { 691 InodeTree.ResolveResult<AbstractFileSystem> res = 692 fsState.resolve(getUriPath(path), true); 693 return res.targetFileSystem.getXAttrs(res.remainingPath); 694 } 695 696 @Override 697 public Map<String, byte[]> getXAttrs(Path path, List<String> names) 698 throws IOException { 699 InodeTree.ResolveResult<AbstractFileSystem> res = 700 fsState.resolve(getUriPath(path), true); 701 return res.targetFileSystem.getXAttrs(res.remainingPath, names); 702 } 703 704 @Override 705 public List<String> listXAttrs(Path path) throws IOException { 706 InodeTree.ResolveResult<AbstractFileSystem> res = 707 fsState.resolve(getUriPath(path), true); 708 return res.targetFileSystem.listXAttrs(res.remainingPath); 709 } 710 711 @Override 712 public void removeXAttr(Path path, String name) throws IOException { 713 InodeTree.ResolveResult<AbstractFileSystem> res = 714 fsState.resolve(getUriPath(path), true); 715 res.targetFileSystem.removeXAttr(res.remainingPath, name); 716 } 717 718 719 /* 720 * An instance of this class represents an internal dir of the viewFs 721 * ie internal dir of the mount table. 722 * It is a ready only mount tbale and create, mkdir or delete operations 723 * are not allowed. 724 * If called on create or mkdir then this target is the parent of the 725 * directory in which one is trying to create or mkdir; hence 726 * in this case the path name passed in is the last component. 727 * Otherwise this target is the end point of the path and hence 728 * the path name passed in is null. 729 */ 730 static class InternalDirOfViewFs extends AbstractFileSystem { 731 732 final InodeTree.INodeDir<AbstractFileSystem> theInternalDir; 733 final long creationTime; // of the the mount table 734 final UserGroupInformation ugi; // the user/group of user who created mtable 735 final URI myUri; // the URI of the outer ViewFs 736 737 public InternalDirOfViewFs(final InodeTree.INodeDir<AbstractFileSystem> dir, 738 final long cTime, final UserGroupInformation ugi, final URI uri) 739 throws URISyntaxException { 740 super(FsConstants.VIEWFS_URI, FsConstants.VIEWFS_SCHEME, false, -1); 741 theInternalDir = dir; 742 creationTime = cTime; 743 this.ugi = ugi; 744 myUri = uri; 745 } 746 747 static private void checkPathIsSlash(final Path f) throws IOException { 748 if (f != InodeTree.SlashPath) { 749 throw new IOException ( 750 "Internal implementation error: expected file name to be /" ); 751 } 752 } 753 754 @Override 755 public FSDataOutputStream createInternal(final Path f, 756 final EnumSet<CreateFlag> flag, final FsPermission absolutePermission, 757 final int bufferSize, final short replication, final long blockSize, 758 final Progressable progress, final ChecksumOpt checksumOpt, 759 final boolean createParent) throws AccessControlException, 760 FileAlreadyExistsException, FileNotFoundException, 761 ParentNotDirectoryException, UnsupportedFileSystemException, 762 UnresolvedLinkException, IOException { 763 throw readOnlyMountTable("create", f); 764 } 765 766 @Override 767 public boolean delete(final Path f, final boolean recursive) 768 throws AccessControlException, IOException { 769 checkPathIsSlash(f); 770 throw readOnlyMountTable("delete", f); 771 } 772 773 @Override 774 public BlockLocation[] getFileBlockLocations(final Path f, final long start, 775 final long len) throws FileNotFoundException, IOException { 776 checkPathIsSlash(f); 777 throw new FileNotFoundException("Path points to dir not a file"); 778 } 779 780 @Override 781 public FileChecksum getFileChecksum(final Path f) 782 throws FileNotFoundException, IOException { 783 checkPathIsSlash(f); 784 throw new FileNotFoundException("Path points to dir not a file"); 785 } 786 787 @Override 788 public FileStatus getFileStatus(final Path f) throws IOException { 789 checkPathIsSlash(f); 790 return new FileStatus(0, true, 0, 0, creationTime, creationTime, 791 PERMISSION_555, ugi.getUserName(), ugi.getGroupNames()[0], 792 new Path(theInternalDir.fullPath).makeQualified( 793 myUri, null)); 794 } 795 796 @Override 797 public FileStatus getFileLinkStatus(final Path f) 798 throws FileNotFoundException { 799 // look up i internalDirs children - ignore first Slash 800 INode<AbstractFileSystem> inode = 801 theInternalDir.children.get(f.toUri().toString().substring(1)); 802 if (inode == null) { 803 throw new FileNotFoundException( 804 "viewFs internal mount table - missing entry:" + f); 805 } 806 FileStatus result; 807 if (inode instanceof INodeLink) { 808 INodeLink<AbstractFileSystem> inodelink = 809 (INodeLink<AbstractFileSystem>) inode; 810 result = new FileStatus(0, false, 0, 0, creationTime, creationTime, 811 PERMISSION_555, ugi.getUserName(), ugi.getGroupNames()[0], 812 inodelink.getTargetLink(), 813 new Path(inode.fullPath).makeQualified( 814 myUri, null)); 815 } else { 816 result = new FileStatus(0, true, 0, 0, creationTime, creationTime, 817 PERMISSION_555, ugi.getUserName(), ugi.getGroupNames()[0], 818 new Path(inode.fullPath).makeQualified( 819 myUri, null)); 820 } 821 return result; 822 } 823 824 @Override 825 public FsStatus getFsStatus() { 826 return new FsStatus(0, 0, 0); 827 } 828 829 @Override 830 public FsServerDefaults getServerDefaults() throws IOException { 831 throw new IOException("FsServerDefaults not implemented yet"); 832 } 833 834 @Override 835 public int getUriDefaultPort() { 836 return -1; 837 } 838 839 @Override 840 public FileStatus[] listStatus(final Path f) throws AccessControlException, 841 IOException { 842 checkPathIsSlash(f); 843 FileStatus[] result = new FileStatus[theInternalDir.children.size()]; 844 int i = 0; 845 for (Entry<String, INode<AbstractFileSystem>> iEntry : 846 theInternalDir.children.entrySet()) { 847 INode<AbstractFileSystem> inode = iEntry.getValue(); 848 849 850 if (inode instanceof INodeLink ) { 851 INodeLink<AbstractFileSystem> link = 852 (INodeLink<AbstractFileSystem>) inode; 853 854 result[i++] = new FileStatus(0, false, 0, 0, 855 creationTime, creationTime, 856 PERMISSION_555, ugi.getUserName(), ugi.getGroupNames()[0], 857 link.getTargetLink(), 858 new Path(inode.fullPath).makeQualified( 859 myUri, null)); 860 } else { 861 result[i++] = new FileStatus(0, true, 0, 0, 862 creationTime, creationTime, 863 PERMISSION_555, ugi.getUserName(), ugi.getGroupNames()[0], 864 new Path(inode.fullPath).makeQualified( 865 myUri, null)); 866 } 867 } 868 return result; 869 } 870 871 @Override 872 public void mkdir(final Path dir, final FsPermission permission, 873 final boolean createParent) throws AccessControlException, 874 FileAlreadyExistsException { 875 if (theInternalDir.isRoot && dir == null) { 876 throw new FileAlreadyExistsException("/ already exits"); 877 } 878 throw readOnlyMountTable("mkdir", dir); 879 } 880 881 @Override 882 public FSDataInputStream open(final Path f, final int bufferSize) 883 throws FileNotFoundException, IOException { 884 checkPathIsSlash(f); 885 throw new FileNotFoundException("Path points to dir not a file"); 886 } 887 888 @Override 889 public boolean truncate(final Path f, final long newLength) 890 throws FileNotFoundException, IOException { 891 checkPathIsSlash(f); 892 throw readOnlyMountTable("truncate", f); 893 } 894 895 @Override 896 public void renameInternal(final Path src, final Path dst) 897 throws AccessControlException, IOException { 898 checkPathIsSlash(src); 899 checkPathIsSlash(dst); 900 throw readOnlyMountTable("rename", src); 901 } 902 903 @Override 904 public boolean supportsSymlinks() { 905 return true; 906 } 907 908 @Override 909 public void createSymlink(final Path target, final Path link, 910 final boolean createParent) throws AccessControlException { 911 throw readOnlyMountTable("createSymlink", link); 912 } 913 914 @Override 915 public Path getLinkTarget(final Path f) throws FileNotFoundException, 916 IOException { 917 return getFileLinkStatus(f).getSymlink(); 918 } 919 920 @Override 921 public void setOwner(final Path f, final String username, 922 final String groupname) throws AccessControlException, IOException { 923 checkPathIsSlash(f); 924 throw readOnlyMountTable("setOwner", f); 925 } 926 927 @Override 928 public void setPermission(final Path f, final FsPermission permission) 929 throws AccessControlException, IOException { 930 checkPathIsSlash(f); 931 throw readOnlyMountTable("setPermission", f); 932 } 933 934 @Override 935 public boolean setReplication(final Path f, final short replication) 936 throws AccessControlException, IOException { 937 checkPathIsSlash(f); 938 throw readOnlyMountTable("setReplication", f); 939 } 940 941 @Override 942 public void setTimes(final Path f, final long mtime, final long atime) 943 throws AccessControlException, IOException { 944 checkPathIsSlash(f); 945 throw readOnlyMountTable("setTimes", f); 946 } 947 948 @Override 949 public void setVerifyChecksum(final boolean verifyChecksum) 950 throws AccessControlException { 951 throw readOnlyMountTable("setVerifyChecksum", ""); 952 } 953 954 @Override 955 public void modifyAclEntries(Path path, List<AclEntry> aclSpec) 956 throws IOException { 957 checkPathIsSlash(path); 958 throw readOnlyMountTable("modifyAclEntries", path); 959 } 960 961 @Override 962 public void removeAclEntries(Path path, List<AclEntry> aclSpec) 963 throws IOException { 964 checkPathIsSlash(path); 965 throw readOnlyMountTable("removeAclEntries", path); 966 } 967 968 @Override 969 public void removeDefaultAcl(Path path) throws IOException { 970 checkPathIsSlash(path); 971 throw readOnlyMountTable("removeDefaultAcl", path); 972 } 973 974 @Override 975 public void removeAcl(Path path) throws IOException { 976 checkPathIsSlash(path); 977 throw readOnlyMountTable("removeAcl", path); 978 } 979 980 @Override 981 public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException { 982 checkPathIsSlash(path); 983 throw readOnlyMountTable("setAcl", path); 984 } 985 986 @Override 987 public AclStatus getAclStatus(Path path) throws IOException { 988 checkPathIsSlash(path); 989 return new AclStatus.Builder().owner(ugi.getUserName()) 990 .group(ugi.getGroupNames()[0]) 991 .addEntries(AclUtil.getMinimalAcl(PERMISSION_555)) 992 .stickyBit(false).build(); 993 } 994 995 @Override 996 public void setXAttr(Path path, String name, byte[] value, 997 EnumSet<XAttrSetFlag> flag) throws IOException { 998 checkPathIsSlash(path); 999 throw readOnlyMountTable("setXAttr", path); 1000 } 1001 1002 @Override 1003 public byte[] getXAttr(Path path, String name) throws IOException { 1004 throw new NotInMountpointException(path, "getXAttr"); 1005 } 1006 1007 @Override 1008 public Map<String, byte[]> getXAttrs(Path path) throws IOException { 1009 throw new NotInMountpointException(path, "getXAttrs"); 1010 } 1011 1012 @Override 1013 public Map<String, byte[]> getXAttrs(Path path, List<String> names) 1014 throws IOException { 1015 throw new NotInMountpointException(path, "getXAttrs"); 1016 } 1017 1018 @Override 1019 public List<String> listXAttrs(Path path) throws IOException { 1020 throw new NotInMountpointException(path, "listXAttrs"); 1021 } 1022 1023 @Override 1024 public void removeXAttr(Path path, String name) throws IOException { 1025 checkPathIsSlash(path); 1026 throw readOnlyMountTable("removeXAttr", path); 1027 } 1028 } 1029}