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