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