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.Arrays;
027 import java.util.EnumSet;
028 import java.util.HashSet;
029 import java.util.List;
030 import java.util.Set;
031 import java.util.StringTokenizer;
032 import java.util.Map.Entry;
033
034 import org.apache.hadoop.classification.InterfaceAudience;
035 import org.apache.hadoop.classification.InterfaceStability;
036 import org.apache.hadoop.conf.Configuration;
037 import org.apache.hadoop.fs.BlockLocation;
038 import org.apache.hadoop.fs.ContentSummary;
039 import org.apache.hadoop.fs.CreateFlag;
040 import org.apache.hadoop.fs.FSDataInputStream;
041 import org.apache.hadoop.fs.FSDataOutputStream;
042 import org.apache.hadoop.fs.FileAlreadyExistsException;
043 import org.apache.hadoop.fs.FileChecksum;
044 import org.apache.hadoop.fs.FileStatus;
045 import org.apache.hadoop.fs.FileSystem;
046 import org.apache.hadoop.fs.FsConstants;
047 import org.apache.hadoop.fs.FsServerDefaults;
048 import org.apache.hadoop.fs.InvalidPathException;
049 import org.apache.hadoop.fs.Path;
050 import org.apache.hadoop.fs.UnsupportedFileSystemException;
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.util.Progressable;
057 import org.apache.hadoop.util.Time;
058
059 /**
060 * ViewFileSystem (extends the FileSystem interface) implements a client-side
061 * mount table. Its spec and implementation is identical to {@link ViewFs}.
062 */
063
064 @InterfaceAudience.Public
065 @InterfaceStability.Evolving /*Evolving for a release,to be changed to Stable */
066 public class ViewFileSystem extends FileSystem {
067 static AccessControlException readOnlyMountTable(final String operation,
068 final String p) {
069 return new AccessControlException(
070 "InternalDir of ViewFileSystem is readonly; operation=" + operation +
071 "Path=" + p);
072 }
073 static AccessControlException readOnlyMountTable(final String operation,
074 final Path p) {
075 return readOnlyMountTable(operation, p.toString());
076 }
077
078 static public class MountPoint {
079 private Path src; // the src of the mount
080 private URI[] targets; // target of the mount; Multiple targets imply mergeMount
081 MountPoint(Path srcPath, URI[] targetURIs) {
082 src = srcPath;
083 targets = targetURIs;
084 }
085 Path getSrc() {
086 return src;
087 }
088 URI[] getTargets() {
089 return targets;
090 }
091 }
092
093 final long creationTime; // of the the mount table
094 final UserGroupInformation ugi; // the user/group of user who created mtable
095 URI myUri;
096 private Path workingDir;
097 Configuration config;
098 InodeTree<FileSystem> fsState; // the fs state; ie the mount table
099 Path homeDir = null;
100
101 /**
102 * Prohibits names which contain a ".", "..", ":" or "/"
103 */
104 private static boolean isValidName(final String src) {
105 // Check for ".." "." ":" "/"
106 final StringTokenizer tokens = new StringTokenizer(src, Path.SEPARATOR);
107 while(tokens.hasMoreTokens()) {
108 String element = tokens.nextToken();
109 if (element.equals("..") ||
110 element.equals(".") ||
111 (element.indexOf(":") >= 0)) {
112 return false;
113 }
114 }
115 return true;
116 }
117
118 /**
119 * Make the path Absolute and get the path-part of a pathname.
120 * Checks that URI matches this file system
121 * and that the path-part is a valid name.
122 *
123 * @param p path
124 * @return path-part of the Path p
125 */
126 private String getUriPath(final Path p) {
127 checkPath(p);
128 String s = makeAbsolute(p).toUri().getPath();
129 if (!isValidName(s)) {
130 throw new InvalidPathException("Path part " + s + " from URI" + p
131 + " is not a valid filename.");
132 }
133 return s;
134 }
135
136 private Path makeAbsolute(final Path f) {
137 return f.isAbsolute() ? f : new Path(workingDir, f);
138 }
139
140 /**
141 * This is the constructor with the signature needed by
142 * {@link FileSystem#createFileSystem(URI, Configuration)}
143 *
144 * After this constructor is called initialize() is called.
145 * @throws IOException
146 */
147 public ViewFileSystem() throws IOException {
148 ugi = UserGroupInformation.getCurrentUser();
149 creationTime = Time.now();
150 }
151
152 /**
153 * Return the protocol scheme for the FileSystem.
154 * <p/>
155 *
156 * @return <code>viewfs</code>
157 */
158 @Override
159 public String getScheme() {
160 return "viewfs";
161 }
162
163 /**
164 * Called after a new FileSystem instance is constructed.
165 * @param theUri a uri whose authority section names the host, port, etc. for
166 * this FileSystem
167 * @param conf the configuration
168 */
169 @Override
170 public void initialize(final URI theUri, final Configuration conf)
171 throws IOException {
172 super.initialize(theUri, conf);
173 setConf(conf);
174 config = conf;
175 // Now build client side view (i.e. client side mount table) from config.
176 final String authority = theUri.getAuthority();
177 try {
178 myUri = new URI(FsConstants.VIEWFS_SCHEME, authority, "/", null, null);
179 fsState = new InodeTree<FileSystem>(conf, authority) {
180
181 @Override
182 protected
183 FileSystem getTargetFileSystem(final URI uri)
184 throws URISyntaxException, IOException {
185 return new ChRootedFileSystem(uri, config);
186 }
187
188 @Override
189 protected
190 FileSystem getTargetFileSystem(final INodeDir<FileSystem> dir)
191 throws URISyntaxException {
192 return new InternalDirOfViewFs(dir, creationTime, ugi, myUri);
193 }
194
195 @Override
196 protected
197 FileSystem getTargetFileSystem(URI[] mergeFsURIList)
198 throws URISyntaxException, UnsupportedFileSystemException {
199 throw new UnsupportedFileSystemException("mergefs not implemented");
200 // return MergeFs.createMergeFs(mergeFsURIList, config);
201 }
202 };
203 workingDir = this.getHomeDirectory();
204 } catch (URISyntaxException e) {
205 throw new IOException("URISyntax exception: " + theUri);
206 }
207
208 }
209
210
211 /**
212 * Convenience Constructor for apps to call directly
213 * @param theUri which must be that of ViewFileSystem
214 * @param conf
215 * @throws IOException
216 */
217 ViewFileSystem(final URI theUri, final Configuration conf)
218 throws IOException {
219 this();
220 initialize(theUri, conf);
221 }
222
223 /**
224 * Convenience Constructor for apps to call directly
225 * @param conf
226 * @throws IOException
227 */
228 public ViewFileSystem(final Configuration conf) throws IOException {
229 this(FsConstants.VIEWFS_URI, conf);
230 }
231
232 public Path getTrashCanLocation(final Path f) throws FileNotFoundException {
233 final InodeTree.ResolveResult<FileSystem> res =
234 fsState.resolve(getUriPath(f), true);
235 return res.isInternalDir() ? null : res.targetFileSystem.getHomeDirectory();
236 }
237
238 @Override
239 public URI getUri() {
240 return myUri;
241 }
242
243 @Override
244 public Path resolvePath(final Path f)
245 throws IOException {
246 final InodeTree.ResolveResult<FileSystem> res;
247 res = fsState.resolve(getUriPath(f), true);
248 if (res.isInternalDir()) {
249 return f;
250 }
251 return res.targetFileSystem.resolvePath(res.remainingPath);
252 }
253
254 @Override
255 public Path getHomeDirectory() {
256 if (homeDir == null) {
257 String base = fsState.getHomeDirPrefixValue();
258 if (base == null) {
259 base = "/user";
260 }
261 homeDir = (base.equals("/") ?
262 this.makeQualified(new Path(base + ugi.getShortUserName())):
263 this.makeQualified(new Path(base + "/" + ugi.getShortUserName())));
264 }
265 return homeDir;
266 }
267
268 @Override
269 public Path getWorkingDirectory() {
270 return workingDir;
271 }
272
273 @Override
274 public void setWorkingDirectory(final Path new_dir) {
275 getUriPath(new_dir); // this validates the path
276 workingDir = makeAbsolute(new_dir);
277 }
278
279 @Override
280 public FSDataOutputStream append(final Path f, final int bufferSize,
281 final Progressable progress) throws IOException {
282 InodeTree.ResolveResult<FileSystem> res =
283 fsState.resolve(getUriPath(f), true);
284 return res.targetFileSystem.append(res.remainingPath, bufferSize, progress);
285 }
286
287 @Override
288 public FSDataOutputStream createNonRecursive(Path f, FsPermission permission,
289 EnumSet<CreateFlag> flags, int bufferSize, short replication, long blockSize,
290 Progressable progress) throws IOException {
291 InodeTree.ResolveResult<FileSystem> res;
292 try {
293 res = fsState.resolve(getUriPath(f), false);
294 } catch (FileNotFoundException e) {
295 throw readOnlyMountTable("create", f);
296 }
297 assert(res.remainingPath != null);
298 return res.targetFileSystem.createNonRecursive(res.remainingPath, permission,
299 flags, bufferSize, replication, blockSize, progress);
300 }
301
302 @Override
303 public FSDataOutputStream create(final Path f, final FsPermission permission,
304 final boolean overwrite, final int bufferSize, final short replication,
305 final long blockSize, final Progressable progress) throws IOException {
306 InodeTree.ResolveResult<FileSystem> res;
307 try {
308 res = fsState.resolve(getUriPath(f), false);
309 } catch (FileNotFoundException e) {
310 throw readOnlyMountTable("create", f);
311 }
312 assert(res.remainingPath != null);
313 return res.targetFileSystem.create(res.remainingPath, permission,
314 overwrite, bufferSize, replication, blockSize, progress);
315 }
316
317
318 @Override
319 public boolean delete(final Path f, final boolean recursive)
320 throws AccessControlException, FileNotFoundException,
321 IOException {
322 InodeTree.ResolveResult<FileSystem> res =
323 fsState.resolve(getUriPath(f), true);
324 // If internal dir or target is a mount link (ie remainingPath is Slash)
325 if (res.isInternalDir() || res.remainingPath == InodeTree.SlashPath) {
326 throw readOnlyMountTable("delete", f);
327 }
328 return res.targetFileSystem.delete(res.remainingPath, recursive);
329 }
330
331 @Override
332 @SuppressWarnings("deprecation")
333 public boolean delete(final Path f)
334 throws AccessControlException, FileNotFoundException,
335 IOException {
336 return delete(f, true);
337 }
338
339 @Override
340 public BlockLocation[] getFileBlockLocations(FileStatus fs,
341 long start, long len) throws IOException {
342 final InodeTree.ResolveResult<FileSystem> res =
343 fsState.resolve(getUriPath(fs.getPath()), true);
344 return res.targetFileSystem.getFileBlockLocations(
345 new ViewFsFileStatus(fs, res.remainingPath), start, len);
346 }
347
348 @Override
349 public FileChecksum getFileChecksum(final Path f)
350 throws AccessControlException, FileNotFoundException,
351 IOException {
352 InodeTree.ResolveResult<FileSystem> res =
353 fsState.resolve(getUriPath(f), true);
354 return res.targetFileSystem.getFileChecksum(res.remainingPath);
355 }
356
357 @Override
358 public FileStatus getFileStatus(final Path f) throws AccessControlException,
359 FileNotFoundException, IOException {
360 InodeTree.ResolveResult<FileSystem> res =
361 fsState.resolve(getUriPath(f), true);
362
363 // FileStatus#getPath is a fully qualified path relative to the root of
364 // target file system.
365 // We need to change it to viewfs URI - relative to root of mount table.
366
367 // The implementors of RawLocalFileSystem were trying to be very smart.
368 // They implement FileStatus#getOwener lazily -- the object
369 // returned is really a RawLocalFileSystem that expect the
370 // FileStatus#getPath to be unchanged so that it can get owner when needed.
371 // Hence we need to interpose a new ViewFileSystemFileStatus that
372 // works around.
373 FileStatus status = res.targetFileSystem.getFileStatus(res.remainingPath);
374 return new ViewFsFileStatus(status, this.makeQualified(f));
375 }
376
377
378 @Override
379 public FileStatus[] listStatus(final Path f) throws AccessControlException,
380 FileNotFoundException, IOException {
381 InodeTree.ResolveResult<FileSystem> res =
382 fsState.resolve(getUriPath(f), true);
383
384 FileStatus[] statusLst = res.targetFileSystem.listStatus(res.remainingPath);
385 if (!res.isInternalDir()) {
386 // We need to change the name in the FileStatus as described in
387 // {@link #getFileStatus }
388 ChRootedFileSystem targetFs;
389 targetFs = (ChRootedFileSystem) res.targetFileSystem;
390 int i = 0;
391 for (FileStatus status : statusLst) {
392 String suffix = targetFs.stripOutRoot(status.getPath());
393 statusLst[i++] = new ViewFsFileStatus(status, this.makeQualified(
394 suffix.length() == 0 ? f : new Path(res.resolvedPath, suffix)));
395 }
396 }
397 return statusLst;
398 }
399
400 @Override
401 public boolean mkdirs(final Path dir, final FsPermission permission)
402 throws IOException {
403 InodeTree.ResolveResult<FileSystem> res =
404 fsState.resolve(getUriPath(dir), false);
405 return res.targetFileSystem.mkdirs(res.remainingPath, permission);
406 }
407
408 @Override
409 public FSDataInputStream open(final Path f, final int bufferSize)
410 throws AccessControlException, FileNotFoundException,
411 IOException {
412 InodeTree.ResolveResult<FileSystem> res =
413 fsState.resolve(getUriPath(f), true);
414 return res.targetFileSystem.open(res.remainingPath, bufferSize);
415 }
416
417
418 @Override
419 public boolean rename(final Path src, final Path dst) throws IOException {
420 // passing resolveLastComponet as false to catch renaming a mount point to
421 // itself. We need to catch this as an internal operation and fail.
422 InodeTree.ResolveResult<FileSystem> resSrc =
423 fsState.resolve(getUriPath(src), false);
424
425 if (resSrc.isInternalDir()) {
426 throw readOnlyMountTable("rename", src);
427 }
428
429 InodeTree.ResolveResult<FileSystem> resDst =
430 fsState.resolve(getUriPath(dst), false);
431 if (resDst.isInternalDir()) {
432 throw readOnlyMountTable("rename", dst);
433 }
434 /**
435 // Alternate 1: renames within same file system - valid but we disallow
436 // Alternate 2: (as described in next para - valid but we have disallowed it
437 //
438 // Note we compare the URIs. the URIs include the link targets.
439 // hence we allow renames across mount links as long as the mount links
440 // point to the same target.
441 if (!resSrc.targetFileSystem.getUri().equals(
442 resDst.targetFileSystem.getUri())) {
443 throw new IOException("Renames across Mount points not supported");
444 }
445 */
446
447 //
448 // Alternate 3 : renames ONLY within the the same mount links.
449 //
450 if (resSrc.targetFileSystem !=resDst.targetFileSystem) {
451 throw new IOException("Renames across Mount points not supported");
452 }
453 return resSrc.targetFileSystem.rename(resSrc.remainingPath,
454 resDst.remainingPath);
455 }
456
457 @Override
458 public void setOwner(final Path f, final String username,
459 final String groupname) throws AccessControlException,
460 FileNotFoundException,
461 IOException {
462 InodeTree.ResolveResult<FileSystem> res =
463 fsState.resolve(getUriPath(f), true);
464 res.targetFileSystem.setOwner(res.remainingPath, username, groupname);
465 }
466
467 @Override
468 public void setPermission(final Path f, final FsPermission permission)
469 throws AccessControlException, FileNotFoundException,
470 IOException {
471 InodeTree.ResolveResult<FileSystem> res =
472 fsState.resolve(getUriPath(f), true);
473 res.targetFileSystem.setPermission(res.remainingPath, permission);
474 }
475
476 @Override
477 public boolean setReplication(final Path f, final short replication)
478 throws AccessControlException, FileNotFoundException,
479 IOException {
480 InodeTree.ResolveResult<FileSystem> res =
481 fsState.resolve(getUriPath(f), true);
482 return res.targetFileSystem.setReplication(res.remainingPath, replication);
483 }
484
485 @Override
486 public void setTimes(final Path f, final long mtime, final long atime)
487 throws AccessControlException, FileNotFoundException,
488 IOException {
489 InodeTree.ResolveResult<FileSystem> res =
490 fsState.resolve(getUriPath(f), true);
491 res.targetFileSystem.setTimes(res.remainingPath, mtime, atime);
492 }
493
494 @Override
495 public void setVerifyChecksum(final boolean verifyChecksum) {
496 List<InodeTree.MountPoint<FileSystem>> mountPoints =
497 fsState.getMountPoints();
498 for (InodeTree.MountPoint<FileSystem> mount : mountPoints) {
499 mount.target.targetFileSystem.setVerifyChecksum(verifyChecksum);
500 }
501 }
502
503 @Override
504 public long getDefaultBlockSize() {
505 throw new NotInMountpointException("getDefaultBlockSize");
506 }
507
508 @Override
509 public short getDefaultReplication() {
510 throw new NotInMountpointException("getDefaultReplication");
511 }
512
513 @Override
514 public FsServerDefaults getServerDefaults() throws IOException {
515 throw new NotInMountpointException("getServerDefaults");
516 }
517
518 @Override
519 public long getDefaultBlockSize(Path f) {
520 try {
521 InodeTree.ResolveResult<FileSystem> res =
522 fsState.resolve(getUriPath(f), true);
523 return res.targetFileSystem.getDefaultBlockSize(res.remainingPath);
524 } catch (FileNotFoundException e) {
525 throw new NotInMountpointException(f, "getDefaultBlockSize");
526 }
527 }
528
529 @Override
530 public short getDefaultReplication(Path f) {
531 try {
532 InodeTree.ResolveResult<FileSystem> res =
533 fsState.resolve(getUriPath(f), true);
534 return res.targetFileSystem.getDefaultReplication(res.remainingPath);
535 } catch (FileNotFoundException e) {
536 throw new NotInMountpointException(f, "getDefaultReplication");
537 }
538 }
539
540 @Override
541 public FsServerDefaults getServerDefaults(Path f) throws IOException {
542 InodeTree.ResolveResult<FileSystem> res =
543 fsState.resolve(getUriPath(f), true);
544 return res.targetFileSystem.getServerDefaults(res.remainingPath);
545 }
546
547 @Override
548 public ContentSummary getContentSummary(Path f) throws IOException {
549 InodeTree.ResolveResult<FileSystem> res =
550 fsState.resolve(getUriPath(f), true);
551 return res.targetFileSystem.getContentSummary(res.remainingPath);
552 }
553
554 @Override
555 public void setWriteChecksum(final boolean writeChecksum) {
556 List<InodeTree.MountPoint<FileSystem>> mountPoints =
557 fsState.getMountPoints();
558 for (InodeTree.MountPoint<FileSystem> mount : mountPoints) {
559 mount.target.targetFileSystem.setWriteChecksum(writeChecksum);
560 }
561 }
562
563 @Override
564 public FileSystem[] getChildFileSystems() {
565 List<InodeTree.MountPoint<FileSystem>> mountPoints =
566 fsState.getMountPoints();
567 Set<FileSystem> children = new HashSet<FileSystem>();
568 for (InodeTree.MountPoint<FileSystem> mountPoint : mountPoints) {
569 FileSystem targetFs = mountPoint.target.targetFileSystem;
570 children.addAll(Arrays.asList(targetFs.getChildFileSystems()));
571 }
572 return children.toArray(new FileSystem[]{});
573 }
574
575 public MountPoint[] getMountPoints() {
576 List<InodeTree.MountPoint<FileSystem>> mountPoints =
577 fsState.getMountPoints();
578
579 MountPoint[] result = new MountPoint[mountPoints.size()];
580 for ( int i = 0; i < mountPoints.size(); ++i ) {
581 result[i] = new MountPoint(new Path(mountPoints.get(i).src),
582 mountPoints.get(i).target.targetDirLinkList);
583 }
584 return result;
585 }
586
587 /*
588 * An instance of this class represents an internal dir of the viewFs
589 * that is internal dir of the mount table.
590 * It is a read only mount tables and create, mkdir or delete operations
591 * are not allowed.
592 * If called on create or mkdir then this target is the parent of the
593 * directory in which one is trying to create or mkdir; hence
594 * in this case the path name passed in is the last component.
595 * Otherwise this target is the end point of the path and hence
596 * the path name passed in is null.
597 */
598 static class InternalDirOfViewFs extends FileSystem {
599 final InodeTree.INodeDir<FileSystem> theInternalDir;
600 final long creationTime; // of the the mount table
601 final UserGroupInformation ugi; // the user/group of user who created mtable
602 final URI myUri;
603
604 public InternalDirOfViewFs(final InodeTree.INodeDir<FileSystem> dir,
605 final long cTime, final UserGroupInformation ugi, URI uri)
606 throws URISyntaxException {
607 myUri = uri;
608 try {
609 initialize(myUri, new Configuration());
610 } catch (IOException e) {
611 throw new RuntimeException("Cannot occur");
612 }
613 theInternalDir = dir;
614 creationTime = cTime;
615 this.ugi = ugi;
616 }
617
618 static private void checkPathIsSlash(final Path f) throws IOException {
619 if (f != InodeTree.SlashPath) {
620 throw new IOException (
621 "Internal implementation error: expected file name to be /" );
622 }
623 }
624
625 @Override
626 public URI getUri() {
627 return myUri;
628 }
629
630 @Override
631 public Path getWorkingDirectory() {
632 throw new RuntimeException (
633 "Internal impl error: getWorkingDir should not have been called" );
634 }
635
636 @Override
637 public void setWorkingDirectory(final Path new_dir) {
638 throw new RuntimeException (
639 "Internal impl error: getWorkingDir should not have been called" );
640 }
641
642 @Override
643 public FSDataOutputStream append(final Path f, final int bufferSize,
644 final Progressable progress) throws IOException {
645 throw readOnlyMountTable("append", f);
646 }
647
648 @Override
649 public FSDataOutputStream create(final Path f,
650 final FsPermission permission, final boolean overwrite,
651 final int bufferSize, final short replication, final long blockSize,
652 final Progressable progress) throws AccessControlException {
653 throw readOnlyMountTable("create", f);
654 }
655
656 @Override
657 public boolean delete(final Path f, final boolean recursive)
658 throws AccessControlException, IOException {
659 checkPathIsSlash(f);
660 throw readOnlyMountTable("delete", f);
661 }
662
663 @Override
664 @SuppressWarnings("deprecation")
665 public boolean delete(final Path f)
666 throws AccessControlException, IOException {
667 return delete(f, true);
668 }
669
670 @Override
671 public BlockLocation[] getFileBlockLocations(final FileStatus fs,
672 final long start, final long len) throws
673 FileNotFoundException, IOException {
674 checkPathIsSlash(fs.getPath());
675 throw new FileNotFoundException("Path points to dir not a file");
676 }
677
678 @Override
679 public FileChecksum getFileChecksum(final Path f)
680 throws FileNotFoundException, IOException {
681 checkPathIsSlash(f);
682 throw new FileNotFoundException("Path points to dir not a file");
683 }
684
685 @Override
686 public FileStatus getFileStatus(Path f) throws IOException {
687 checkPathIsSlash(f);
688 return new FileStatus(0, true, 0, 0, creationTime, creationTime,
689 PERMISSION_RRR, ugi.getUserName(), ugi.getGroupNames()[0],
690
691 new Path(theInternalDir.fullPath).makeQualified(
692 myUri, null));
693 }
694
695
696 @Override
697 public FileStatus[] listStatus(Path f) throws AccessControlException,
698 FileNotFoundException, IOException {
699 checkPathIsSlash(f);
700 FileStatus[] result = new FileStatus[theInternalDir.children.size()];
701 int i = 0;
702 for (Entry<String, INode<FileSystem>> iEntry :
703 theInternalDir.children.entrySet()) {
704 INode<FileSystem> inode = iEntry.getValue();
705 if (inode instanceof INodeLink ) {
706 INodeLink<FileSystem> link = (INodeLink<FileSystem>) inode;
707
708 result[i++] = new FileStatus(0, false, 0, 0,
709 creationTime, creationTime, PERMISSION_RRR,
710 ugi.getUserName(), ugi.getGroupNames()[0],
711 link.getTargetLink(),
712 new Path(inode.fullPath).makeQualified(
713 myUri, null));
714 } else {
715 result[i++] = new FileStatus(0, true, 0, 0,
716 creationTime, creationTime, PERMISSION_RRR,
717 ugi.getUserName(), ugi.getGroupNames()[0],
718 new Path(inode.fullPath).makeQualified(
719 myUri, null));
720 }
721 }
722 return result;
723 }
724
725 @Override
726 public boolean mkdirs(Path dir, FsPermission permission)
727 throws AccessControlException, FileAlreadyExistsException {
728 if (theInternalDir.isRoot && dir == null) {
729 throw new FileAlreadyExistsException("/ already exits");
730 }
731 // Note dir starts with /
732 if (theInternalDir.children.containsKey(dir.toString().substring(1))) {
733 return true; // this is the stupid semantics of FileSystem
734 }
735 throw readOnlyMountTable("mkdirs", dir);
736 }
737
738 @Override
739 public FSDataInputStream open(Path f, int bufferSize)
740 throws AccessControlException, FileNotFoundException, IOException {
741 checkPathIsSlash(f);
742 throw new FileNotFoundException("Path points to dir not a file");
743 }
744
745 @Override
746 public boolean rename(Path src, Path dst) throws AccessControlException,
747 IOException {
748 checkPathIsSlash(src);
749 checkPathIsSlash(dst);
750 throw readOnlyMountTable("rename", src);
751 }
752
753 @Override
754 public void setOwner(Path f, String username, String groupname)
755 throws AccessControlException, IOException {
756 checkPathIsSlash(f);
757 throw readOnlyMountTable("setOwner", f);
758 }
759
760 @Override
761 public void setPermission(Path f, FsPermission permission)
762 throws AccessControlException, IOException {
763 checkPathIsSlash(f);
764 throw readOnlyMountTable("setPermission", f);
765 }
766
767 @Override
768 public boolean setReplication(Path f, short replication)
769 throws AccessControlException, IOException {
770 checkPathIsSlash(f);
771 throw readOnlyMountTable("setReplication", f);
772 }
773
774 @Override
775 public void setTimes(Path f, long mtime, long atime)
776 throws AccessControlException, IOException {
777 checkPathIsSlash(f);
778 throw readOnlyMountTable("setTimes", f);
779 }
780
781 @Override
782 public void setVerifyChecksum(boolean verifyChecksum) {
783 // Noop for viewfs
784 }
785
786 @Override
787 public FsServerDefaults getServerDefaults(Path f) throws IOException {
788 throw new NotInMountpointException(f, "getServerDefaults");
789 }
790
791 @Override
792 public long getDefaultBlockSize(Path f) {
793 throw new NotInMountpointException(f, "getDefaultBlockSize");
794 }
795
796 @Override
797 public short getDefaultReplication(Path f) {
798 throw new NotInMountpointException(f, "getDefaultReplication");
799 }
800 }
801 }