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