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 456 @Override 457 public void renameInternal(final Path src, final Path dst, 458 final boolean overwrite) throws IOException, UnresolvedLinkException { 459 // passing resolveLastComponet as false to catch renaming a mount point 460 // itself we need to catch this as an internal operation and fail. 461 InodeTree.ResolveResult<AbstractFileSystem> resSrc = 462 fsState.resolve(getUriPath(src), false); 463 464 if (resSrc.isInternalDir()) { 465 throw new AccessControlException( 466 "Cannot Rename within internal dirs of mount table: src=" + src 467 + " is readOnly"); 468 } 469 470 InodeTree.ResolveResult<AbstractFileSystem> resDst = 471 fsState.resolve(getUriPath(dst), false); 472 if (resDst.isInternalDir()) { 473 throw new AccessControlException( 474 "Cannot Rename within internal dirs of mount table: dest=" + dst 475 + " is readOnly"); 476 } 477 478 /** 479 // Alternate 1: renames within same file system - valid but we disallow 480 // Alternate 2: (as described in next para - valid but we have disallowed it 481 // 482 // Note we compare the URIs. the URIs include the link targets. 483 // hence we allow renames across mount links as long as the mount links 484 // point to the same target. 485 if (!resSrc.targetFileSystem.getUri().equals( 486 resDst.targetFileSystem.getUri())) { 487 throw new IOException("Renames across Mount points not supported"); 488 } 489 */ 490 491 // 492 // Alternate 3 : renames ONLY within the the same mount links. 493 // 494 495 if (resSrc.targetFileSystem !=resDst.targetFileSystem) { 496 throw new IOException("Renames across Mount points not supported"); 497 } 498 499 resSrc.targetFileSystem.renameInternal(resSrc.remainingPath, 500 resDst.remainingPath, overwrite); 501 } 502 503 @Override 504 public void renameInternal(final Path src, final Path dst) 505 throws AccessControlException, FileAlreadyExistsException, 506 FileNotFoundException, ParentNotDirectoryException, 507 UnresolvedLinkException, IOException { 508 renameInternal(src, dst, false); 509 } 510 511 @Override 512 public boolean supportsSymlinks() { 513 return true; 514 } 515 516 @Override 517 public void createSymlink(final Path target, final Path link, 518 final boolean createParent) throws IOException, UnresolvedLinkException { 519 InodeTree.ResolveResult<AbstractFileSystem> res; 520 try { 521 res = fsState.resolve(getUriPath(link), false); 522 } catch (FileNotFoundException e) { 523 if (createParent) { 524 throw readOnlyMountTable("createSymlink", link); 525 } else { 526 throw e; 527 } 528 } 529 assert(res.remainingPath != null); 530 res.targetFileSystem.createSymlink(target, res.remainingPath, 531 createParent); 532 } 533 534 @Override 535 public Path getLinkTarget(final Path f) throws IOException { 536 InodeTree.ResolveResult<AbstractFileSystem> res = 537 fsState.resolve(getUriPath(f), false); // do not follow mount link 538 return res.targetFileSystem.getLinkTarget(res.remainingPath); 539 } 540 541 @Override 542 public void setOwner(final Path f, final String username, 543 final String groupname) throws AccessControlException, 544 FileNotFoundException, UnresolvedLinkException, IOException { 545 InodeTree.ResolveResult<AbstractFileSystem> res = 546 fsState.resolve(getUriPath(f), true); 547 res.targetFileSystem.setOwner(res.remainingPath, username, groupname); 548 } 549 550 @Override 551 public void setPermission(final Path f, final FsPermission permission) 552 throws AccessControlException, FileNotFoundException, 553 UnresolvedLinkException, IOException { 554 InodeTree.ResolveResult<AbstractFileSystem> res = 555 fsState.resolve(getUriPath(f), true); 556 res.targetFileSystem.setPermission(res.remainingPath, permission); 557 558 } 559 560 @Override 561 public boolean setReplication(final Path f, final short replication) 562 throws AccessControlException, FileNotFoundException, 563 UnresolvedLinkException, IOException { 564 InodeTree.ResolveResult<AbstractFileSystem> res = 565 fsState.resolve(getUriPath(f), true); 566 return res.targetFileSystem.setReplication(res.remainingPath, replication); 567 } 568 569 @Override 570 public void setTimes(final Path f, final long mtime, final long atime) 571 throws AccessControlException, FileNotFoundException, 572 UnresolvedLinkException, IOException { 573 InodeTree.ResolveResult<AbstractFileSystem> res = 574 fsState.resolve(getUriPath(f), true); 575 res.targetFileSystem.setTimes(res.remainingPath, mtime, atime); 576 } 577 578 @Override 579 public void setVerifyChecksum(final boolean verifyChecksum) 580 throws AccessControlException, IOException { 581 // This is a file system level operations, however ViewFs 582 // points to many file systems. Noop for ViewFs. 583 } 584 585 public MountPoint[] getMountPoints() { 586 List<InodeTree.MountPoint<AbstractFileSystem>> mountPoints = 587 fsState.getMountPoints(); 588 589 MountPoint[] result = new MountPoint[mountPoints.size()]; 590 for ( int i = 0; i < mountPoints.size(); ++i ) { 591 result[i] = new MountPoint(new Path(mountPoints.get(i).src), 592 mountPoints.get(i).target.targetDirLinkList); 593 } 594 return result; 595 } 596 597 @Override 598 public List<Token<?>> getDelegationTokens(String renewer) throws IOException { 599 List<InodeTree.MountPoint<AbstractFileSystem>> mountPoints = 600 fsState.getMountPoints(); 601 int initialListSize = 0; 602 for (InodeTree.MountPoint<AbstractFileSystem> im : mountPoints) { 603 initialListSize += im.target.targetDirLinkList.length; 604 } 605 List<Token<?>> result = new ArrayList<Token<?>>(initialListSize); 606 for ( int i = 0; i < mountPoints.size(); ++i ) { 607 List<Token<?>> tokens = 608 mountPoints.get(i).target.targetFileSystem.getDelegationTokens(renewer); 609 if (tokens != null) { 610 result.addAll(tokens); 611 } 612 } 613 return result; 614 } 615 616 @Override 617 public boolean isValidName(String src) { 618 // Prefix validated at mount time and rest of path validated by mount target. 619 return true; 620 } 621 622 @Override 623 public void modifyAclEntries(Path path, List<AclEntry> aclSpec) 624 throws IOException { 625 InodeTree.ResolveResult<AbstractFileSystem> res = 626 fsState.resolve(getUriPath(path), true); 627 res.targetFileSystem.modifyAclEntries(res.remainingPath, aclSpec); 628 } 629 630 @Override 631 public void removeAclEntries(Path path, List<AclEntry> aclSpec) 632 throws IOException { 633 InodeTree.ResolveResult<AbstractFileSystem> res = 634 fsState.resolve(getUriPath(path), true); 635 res.targetFileSystem.removeAclEntries(res.remainingPath, aclSpec); 636 } 637 638 @Override 639 public void removeDefaultAcl(Path path) 640 throws IOException { 641 InodeTree.ResolveResult<AbstractFileSystem> res = 642 fsState.resolve(getUriPath(path), true); 643 res.targetFileSystem.removeDefaultAcl(res.remainingPath); 644 } 645 646 @Override 647 public void removeAcl(Path path) 648 throws IOException { 649 InodeTree.ResolveResult<AbstractFileSystem> res = 650 fsState.resolve(getUriPath(path), true); 651 res.targetFileSystem.removeAcl(res.remainingPath); 652 } 653 654 @Override 655 public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException { 656 InodeTree.ResolveResult<AbstractFileSystem> res = 657 fsState.resolve(getUriPath(path), true); 658 res.targetFileSystem.setAcl(res.remainingPath, aclSpec); 659 } 660 661 @Override 662 public AclStatus getAclStatus(Path path) throws IOException { 663 InodeTree.ResolveResult<AbstractFileSystem> res = 664 fsState.resolve(getUriPath(path), true); 665 return res.targetFileSystem.getAclStatus(res.remainingPath); 666 } 667 668 @Override 669 public void setXAttr(Path path, String name, byte[] value, 670 EnumSet<XAttrSetFlag> flag) throws IOException { 671 InodeTree.ResolveResult<AbstractFileSystem> res = 672 fsState.resolve(getUriPath(path), true); 673 res.targetFileSystem.setXAttr(res.remainingPath, name, value, flag); 674 } 675 676 @Override 677 public byte[] getXAttr(Path path, String name) throws IOException { 678 InodeTree.ResolveResult<AbstractFileSystem> res = 679 fsState.resolve(getUriPath(path), true); 680 return res.targetFileSystem.getXAttr(res.remainingPath, name); 681 } 682 683 @Override 684 public Map<String, byte[]> getXAttrs(Path path) throws IOException { 685 InodeTree.ResolveResult<AbstractFileSystem> res = 686 fsState.resolve(getUriPath(path), true); 687 return res.targetFileSystem.getXAttrs(res.remainingPath); 688 } 689 690 @Override 691 public Map<String, byte[]> getXAttrs(Path path, List<String> names) 692 throws IOException { 693 InodeTree.ResolveResult<AbstractFileSystem> res = 694 fsState.resolve(getUriPath(path), true); 695 return res.targetFileSystem.getXAttrs(res.remainingPath, names); 696 } 697 698 @Override 699 public List<String> listXAttrs(Path path) throws IOException { 700 InodeTree.ResolveResult<AbstractFileSystem> res = 701 fsState.resolve(getUriPath(path), true); 702 return res.targetFileSystem.listXAttrs(res.remainingPath); 703 } 704 705 @Override 706 public void removeXAttr(Path path, String name) throws IOException { 707 InodeTree.ResolveResult<AbstractFileSystem> res = 708 fsState.resolve(getUriPath(path), true); 709 res.targetFileSystem.removeXAttr(res.remainingPath, name); 710 } 711 712 713 /* 714 * An instance of this class represents an internal dir of the viewFs 715 * ie internal dir of the mount table. 716 * It is a ready only mount tbale and create, mkdir or delete operations 717 * are not allowed. 718 * If called on create or mkdir then this target is the parent of the 719 * directory in which one is trying to create or mkdir; hence 720 * in this case the path name passed in is the last component. 721 * Otherwise this target is the end point of the path and hence 722 * the path name passed in is null. 723 */ 724 static class InternalDirOfViewFs extends AbstractFileSystem { 725 726 final InodeTree.INodeDir<AbstractFileSystem> theInternalDir; 727 final long creationTime; // of the the mount table 728 final UserGroupInformation ugi; // the user/group of user who created mtable 729 final URI myUri; // the URI of the outer ViewFs 730 731 public InternalDirOfViewFs(final InodeTree.INodeDir<AbstractFileSystem> dir, 732 final long cTime, final UserGroupInformation ugi, final URI uri) 733 throws URISyntaxException { 734 super(FsConstants.VIEWFS_URI, FsConstants.VIEWFS_SCHEME, false, -1); 735 theInternalDir = dir; 736 creationTime = cTime; 737 this.ugi = ugi; 738 myUri = uri; 739 } 740 741 static private void checkPathIsSlash(final Path f) throws IOException { 742 if (f != InodeTree.SlashPath) { 743 throw new IOException ( 744 "Internal implementation error: expected file name to be /" ); 745 } 746 } 747 748 @Override 749 public FSDataOutputStream createInternal(final Path f, 750 final EnumSet<CreateFlag> flag, final FsPermission absolutePermission, 751 final int bufferSize, final short replication, final long blockSize, 752 final Progressable progress, final ChecksumOpt checksumOpt, 753 final boolean createParent) throws AccessControlException, 754 FileAlreadyExistsException, FileNotFoundException, 755 ParentNotDirectoryException, UnsupportedFileSystemException, 756 UnresolvedLinkException, IOException { 757 throw readOnlyMountTable("create", f); 758 } 759 760 @Override 761 public boolean delete(final Path f, final boolean recursive) 762 throws AccessControlException, IOException { 763 checkPathIsSlash(f); 764 throw readOnlyMountTable("delete", f); 765 } 766 767 @Override 768 public BlockLocation[] getFileBlockLocations(final Path f, final long start, 769 final long len) throws FileNotFoundException, IOException { 770 checkPathIsSlash(f); 771 throw new FileNotFoundException("Path points to dir not a file"); 772 } 773 774 @Override 775 public FileChecksum getFileChecksum(final Path f) 776 throws FileNotFoundException, IOException { 777 checkPathIsSlash(f); 778 throw new FileNotFoundException("Path points to dir not a file"); 779 } 780 781 @Override 782 public FileStatus getFileStatus(final Path f) throws IOException { 783 checkPathIsSlash(f); 784 return new FileStatus(0, true, 0, 0, creationTime, creationTime, 785 PERMISSION_555, ugi.getUserName(), ugi.getPrimaryGroupName(), 786 new Path(theInternalDir.fullPath).makeQualified( 787 myUri, null)); 788 } 789 790 @Override 791 public FileStatus getFileLinkStatus(final Path f) 792 throws IOException { 793 // look up i internalDirs children - ignore first Slash 794 INode<AbstractFileSystem> inode = 795 theInternalDir.children.get(f.toUri().toString().substring(1)); 796 if (inode == null) { 797 throw new FileNotFoundException( 798 "viewFs internal mount table - missing entry:" + f); 799 } 800 FileStatus result; 801 if (inode instanceof INodeLink) { 802 INodeLink<AbstractFileSystem> inodelink = 803 (INodeLink<AbstractFileSystem>) inode; 804 result = new FileStatus(0, false, 0, 0, creationTime, creationTime, 805 PERMISSION_555, ugi.getUserName(), ugi.getPrimaryGroupName(), 806 inodelink.getTargetLink(), 807 new Path(inode.fullPath).makeQualified( 808 myUri, null)); 809 } else { 810 result = new FileStatus(0, true, 0, 0, creationTime, creationTime, 811 PERMISSION_555, ugi.getUserName(), ugi.getPrimaryGroupName(), 812 new Path(inode.fullPath).makeQualified( 813 myUri, null)); 814 } 815 return result; 816 } 817 818 @Override 819 public FsStatus getFsStatus() { 820 return new FsStatus(0, 0, 0); 821 } 822 823 @Override 824 public FsServerDefaults getServerDefaults() throws IOException { 825 throw new IOException("FsServerDefaults not implemented yet"); 826 } 827 828 @Override 829 public int getUriDefaultPort() { 830 return -1; 831 } 832 833 @Override 834 public FileStatus[] listStatus(final Path f) throws AccessControlException, 835 IOException { 836 checkPathIsSlash(f); 837 FileStatus[] result = new FileStatus[theInternalDir.children.size()]; 838 int i = 0; 839 for (Entry<String, INode<AbstractFileSystem>> iEntry : 840 theInternalDir.children.entrySet()) { 841 INode<AbstractFileSystem> inode = iEntry.getValue(); 842 843 844 if (inode instanceof INodeLink ) { 845 INodeLink<AbstractFileSystem> link = 846 (INodeLink<AbstractFileSystem>) inode; 847 848 result[i++] = new FileStatus(0, false, 0, 0, 849 creationTime, creationTime, 850 PERMISSION_555, ugi.getUserName(), ugi.getPrimaryGroupName(), 851 link.getTargetLink(), 852 new Path(inode.fullPath).makeQualified( 853 myUri, null)); 854 } else { 855 result[i++] = new FileStatus(0, true, 0, 0, 856 creationTime, creationTime, 857 PERMISSION_555, ugi.getUserName(), ugi.getGroupNames()[0], 858 new Path(inode.fullPath).makeQualified( 859 myUri, null)); 860 } 861 } 862 return result; 863 } 864 865 @Override 866 public void mkdir(final Path dir, final FsPermission permission, 867 final boolean createParent) throws AccessControlException, 868 FileAlreadyExistsException { 869 if (theInternalDir.isRoot && dir == null) { 870 throw new FileAlreadyExistsException("/ already exits"); 871 } 872 throw readOnlyMountTable("mkdir", dir); 873 } 874 875 @Override 876 public FSDataInputStream open(final Path f, final int bufferSize) 877 throws FileNotFoundException, IOException { 878 checkPathIsSlash(f); 879 throw new FileNotFoundException("Path points to dir not a file"); 880 } 881 882 @Override 883 public void renameInternal(final Path src, final Path dst) 884 throws AccessControlException, IOException { 885 checkPathIsSlash(src); 886 checkPathIsSlash(dst); 887 throw readOnlyMountTable("rename", src); 888 } 889 890 @Override 891 public boolean supportsSymlinks() { 892 return true; 893 } 894 895 @Override 896 public void createSymlink(final Path target, final Path link, 897 final boolean createParent) throws AccessControlException { 898 throw readOnlyMountTable("createSymlink", link); 899 } 900 901 @Override 902 public Path getLinkTarget(final Path f) throws FileNotFoundException, 903 IOException { 904 return getFileLinkStatus(f).getSymlink(); 905 } 906 907 @Override 908 public void setOwner(final Path f, final String username, 909 final String groupname) throws AccessControlException, IOException { 910 checkPathIsSlash(f); 911 throw readOnlyMountTable("setOwner", f); 912 } 913 914 @Override 915 public void setPermission(final Path f, final FsPermission permission) 916 throws AccessControlException, IOException { 917 checkPathIsSlash(f); 918 throw readOnlyMountTable("setPermission", f); 919 } 920 921 @Override 922 public boolean setReplication(final Path f, final short replication) 923 throws AccessControlException, IOException { 924 checkPathIsSlash(f); 925 throw readOnlyMountTable("setReplication", f); 926 } 927 928 @Override 929 public void setTimes(final Path f, final long mtime, final long atime) 930 throws AccessControlException, IOException { 931 checkPathIsSlash(f); 932 throw readOnlyMountTable("setTimes", f); 933 } 934 935 @Override 936 public void setVerifyChecksum(final boolean verifyChecksum) 937 throws AccessControlException { 938 throw readOnlyMountTable("setVerifyChecksum", ""); 939 } 940 941 @Override 942 public void modifyAclEntries(Path path, List<AclEntry> aclSpec) 943 throws IOException { 944 checkPathIsSlash(path); 945 throw readOnlyMountTable("modifyAclEntries", path); 946 } 947 948 @Override 949 public void removeAclEntries(Path path, List<AclEntry> aclSpec) 950 throws IOException { 951 checkPathIsSlash(path); 952 throw readOnlyMountTable("removeAclEntries", path); 953 } 954 955 @Override 956 public void removeDefaultAcl(Path path) throws IOException { 957 checkPathIsSlash(path); 958 throw readOnlyMountTable("removeDefaultAcl", path); 959 } 960 961 @Override 962 public void removeAcl(Path path) throws IOException { 963 checkPathIsSlash(path); 964 throw readOnlyMountTable("removeAcl", path); 965 } 966 967 @Override 968 public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException { 969 checkPathIsSlash(path); 970 throw readOnlyMountTable("setAcl", path); 971 } 972 973 @Override 974 public AclStatus getAclStatus(Path path) throws IOException { 975 checkPathIsSlash(path); 976 return new AclStatus.Builder().owner(ugi.getUserName()) 977 .group(ugi.getPrimaryGroupName()) 978 .addEntries(AclUtil.getMinimalAcl(PERMISSION_555)) 979 .stickyBit(false).build(); 980 } 981 982 @Override 983 public void setXAttr(Path path, String name, byte[] value, 984 EnumSet<XAttrSetFlag> flag) throws IOException { 985 checkPathIsSlash(path); 986 throw readOnlyMountTable("setXAttr", path); 987 } 988 989 @Override 990 public byte[] getXAttr(Path path, String name) throws IOException { 991 throw new NotInMountpointException(path, "getXAttr"); 992 } 993 994 @Override 995 public Map<String, byte[]> getXAttrs(Path path) throws IOException { 996 throw new NotInMountpointException(path, "getXAttrs"); 997 } 998 999 @Override 1000 public Map<String, byte[]> getXAttrs(Path path, List<String> names) 1001 throws IOException { 1002 throw new NotInMountpointException(path, "getXAttrs"); 1003 } 1004 1005 @Override 1006 public List<String> listXAttrs(Path path) throws IOException { 1007 throw new NotInMountpointException(path, "listXAttrs"); 1008 } 1009 1010 @Override 1011 public void removeXAttr(Path path, String name) throws IOException { 1012 checkPathIsSlash(path); 1013 throw readOnlyMountTable("removeXAttr", path); 1014 } 1015 } 1016}