1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 package org.apache.hadoop.fs.viewfs;
19 import java.io.FileNotFoundException;
20 import java.io.IOException;
21 import java.net.URI;
22 import java.util.EnumSet;
23 import java.util.List;
24 import java.util.Map;
25 
26 import org.apache.hadoop.classification.InterfaceAudience;
27 import org.apache.hadoop.classification.InterfaceStability;
28 import org.apache.hadoop.conf.Configuration;
29 import org.apache.hadoop.fs.BlockLocation;
30 import org.apache.hadoop.fs.ContentSummary;
31 import org.apache.hadoop.fs.CreateFlag;
32 import org.apache.hadoop.fs.FSDataInputStream;
33 import org.apache.hadoop.fs.FSDataOutputStream;
34 import org.apache.hadoop.fs.FileChecksum;
35 import org.apache.hadoop.fs.FileStatus;
36 import org.apache.hadoop.fs.FileSystem;
37 import org.apache.hadoop.fs.FilterFileSystem;
38 import org.apache.hadoop.fs.FsServerDefaults;
39 import org.apache.hadoop.fs.FsStatus;
40 import org.apache.hadoop.fs.LocatedFileStatus;
41 import org.apache.hadoop.fs.Path;
42 import org.apache.hadoop.fs.XAttrSetFlag;
43 import org.apache.hadoop.fs.RemoteIterator;
44 import org.apache.hadoop.fs.permission.AclEntry;
45 import org.apache.hadoop.fs.permission.AclStatus;
46 import org.apache.hadoop.fs.permission.FsAction;
47 import org.apache.hadoop.fs.permission.FsPermission;
48 import org.apache.hadoop.security.AccessControlException;
49 import org.apache.hadoop.util.Progressable;
50 
51 /**
52  * <code>ChRootedFileSystem</code> is a file system with its root some path
53  * below the root of its base file system.
54  *
55  * Example: For a base file system hdfs://nn1/ with chRoot at /usr/foo, the
56  * members will be setup as shown below.
57  * <ul>
58  * <li>myFs is the base file system and points to hdfs at nn1</li>
59  * <li>myURI is hdfs://nn1/user/foo</li>
60  * <li>chRootPathPart is /user/foo</li>
61  * <li>workingDir is a directory related to chRoot</li>
62  * </ul>
63  *
64  * The paths are resolved as follows by ChRootedFileSystem:
65  * <ul>
66  * <li> Absolute path /a/b/c is resolved to /user/foo/a/b/c at myFs</li>
67  * <li> Relative path x/y is resolved to /user/foo/<workingDir>/x/y</li>
68  * </ul>
69  */
70 
71 @InterfaceAudience.Private
72 @InterfaceStability.Evolving /*Evolving for a release,to be changed to Stable */
73 class ChRootedFileSystem extends FilterFileSystem {
74   private final URI myUri; // the base URI + the chRoot
75   private final Path chRootPathPart; // the root below the root of the base
76   private final String chRootPathPartString;
77   private Path workingDir;
78 
getMyFs()79   protected FileSystem getMyFs() {
80     return getRawFileSystem();
81   }
82 
83   /**
84    * @param path
85    * @return  full path including the chroot
86    */
fullPath(final Path path)87   protected Path fullPath(final Path path) {
88     super.checkPath(path);
89     return path.isAbsolute() ?
90         new Path((chRootPathPart.isRoot() ? "" : chRootPathPartString)
91             + path.toUri().getPath()) :
92         new Path(chRootPathPartString + workingDir.toUri().getPath(), path);
93   }
94 
95   /**
96    * Constructor
97    * @param uri base file system
98    * @param conf configuration
99    * @throws IOException
100    */
ChRootedFileSystem(final URI uri, Configuration conf)101   public ChRootedFileSystem(final URI uri, Configuration conf)
102       throws IOException {
103     super(FileSystem.get(uri, conf));
104     String pathString = uri.getPath();
105     if (pathString.isEmpty()) {
106       pathString = "/";
107     }
108     chRootPathPart = new Path(pathString);
109     chRootPathPartString = chRootPathPart.toUri().getPath();
110     myUri = uri;
111     workingDir = getHomeDirectory();
112     // We don't use the wd of the myFs
113   }
114 
115   /**
116    * Called after a new FileSystem instance is constructed.
117    * @param name a uri whose authority section names the host, port, etc.
118    *   for this FileSystem
119    * @param conf the configuration
120    */
121   @Override
initialize(final URI name, final Configuration conf)122   public void initialize(final URI name, final Configuration conf)
123       throws IOException {
124     super.initialize(name, conf);
125     setConf(conf);
126   }
127 
128   @Override
getUri()129   public URI getUri() {
130     return myUri;
131   }
132 
133   /**
134    * Strip out the root from the path.
135    * @param p - fully qualified path p
136    * @return -  the remaining path  without the begining /
137    * @throws IOException if the p is not prefixed with root
138    */
stripOutRoot(final Path p)139   String stripOutRoot(final Path p) throws IOException {
140     try {
141      checkPath(p);
142     } catch (IllegalArgumentException e) {
143       throw new IOException("Internal Error - path " + p +
144           " should have been with URI: " + myUri);
145     }
146     String pathPart = p.toUri().getPath();
147     return (pathPart.length() == chRootPathPartString.length()) ? "" : pathPart
148         .substring(chRootPathPartString.length() + (chRootPathPart.isRoot() ? 0 : 1));
149   }
150 
151   @Override
getInitialWorkingDirectory()152   protected Path getInitialWorkingDirectory() {
153     /*
154      * 3 choices here:
155      *     null or / or /user/<uname> or strip out the root out of myFs's
156      *  inital wd.
157      * Only reasonable choice for initialWd for chrooted fds is null
158      * so that the default rule for wd is applied
159      */
160     return null;
161   }
162 
getResolvedQualifiedPath(final Path f)163   public Path getResolvedQualifiedPath(final Path f)
164       throws FileNotFoundException {
165     return makeQualified(
166         new Path(chRootPathPartString + f.toUri().toString()));
167   }
168 
169   @Override
getWorkingDirectory()170   public Path getWorkingDirectory() {
171     return workingDir;
172   }
173 
174   @Override
setWorkingDirectory(final Path new_dir)175   public void setWorkingDirectory(final Path new_dir) {
176     workingDir = new_dir.isAbsolute() ? new_dir : new Path(workingDir, new_dir);
177   }
178 
179   @Override
create(final Path f, final FsPermission permission, final boolean overwrite, final int bufferSize, final short replication, final long blockSize, final Progressable progress)180   public FSDataOutputStream create(final Path f, final FsPermission permission,
181       final boolean overwrite, final int bufferSize, final short replication,
182       final long blockSize, final Progressable progress) throws IOException {
183     return super.create(fullPath(f), permission, overwrite, bufferSize,
184         replication, blockSize, progress);
185   }
186 
187   @Override
188   @Deprecated
createNonRecursive(Path f, FsPermission permission, EnumSet<CreateFlag> flags, int bufferSize, short replication, long blockSize, Progressable progress)189   public FSDataOutputStream createNonRecursive(Path f, FsPermission permission,
190       EnumSet<CreateFlag> flags, int bufferSize, short replication, long blockSize,
191       Progressable progress) throws IOException {
192 
193     return super.createNonRecursive(fullPath(f), permission, flags, bufferSize, replication, blockSize,
194         progress);
195   }
196 
197   @Override
delete(final Path f, final boolean recursive)198   public boolean delete(final Path f, final boolean recursive)
199       throws IOException {
200     return super.delete(fullPath(f), recursive);
201   }
202 
203 
204   @Override
205   @SuppressWarnings("deprecation")
delete(Path f)206   public boolean delete(Path f) throws IOException {
207    return delete(f, true);
208   }
209 
210   @Override
getFileBlockLocations(final FileStatus fs, final long start, final long len)211   public BlockLocation[] getFileBlockLocations(final FileStatus fs, final long start,
212       final long len) throws IOException {
213     return super.getFileBlockLocations(
214         new ViewFsFileStatus(fs, fullPath(fs.getPath())), start, len);
215   }
216 
217   @Override
getFileChecksum(final Path f)218   public FileChecksum getFileChecksum(final Path f)
219       throws IOException {
220     return super.getFileChecksum(fullPath(f));
221   }
222 
223   @Override
getFileStatus(final Path f)224   public FileStatus getFileStatus(final Path f)
225       throws IOException {
226     return super.getFileStatus(fullPath(f));
227   }
228 
229   @Override
access(Path path, FsAction mode)230   public void access(Path path, FsAction mode) throws AccessControlException,
231       FileNotFoundException, IOException {
232     super.access(fullPath(path), mode);
233   }
234 
235   @Override
getStatus(Path p)236   public FsStatus getStatus(Path p) throws IOException {
237     return super.getStatus(fullPath(p));
238   }
239 
240   @Override
listStatus(final Path f)241   public FileStatus[] listStatus(final Path f)
242       throws IOException {
243     return super.listStatus(fullPath(f));
244   }
245 
246   @Override
listLocatedStatus(Path f)247   public RemoteIterator<LocatedFileStatus> listLocatedStatus(Path f)
248       throws IOException {
249     return super.listLocatedStatus(fullPath(f));
250   }
251 
252   @Override
mkdirs(final Path f, final FsPermission permission)253   public boolean mkdirs(final Path f, final FsPermission permission)
254       throws IOException {
255     return super.mkdirs(fullPath(f), permission);
256   }
257 
258   @Override
open(final Path f, final int bufferSize)259   public FSDataInputStream open(final Path f, final int bufferSize)
260     throws IOException {
261     return super.open(fullPath(f), bufferSize);
262   }
263 
264   @Override
append(final Path f, final int bufferSize, final Progressable progress)265   public FSDataOutputStream append(final Path f, final int bufferSize,
266       final Progressable progress) throws IOException {
267     return super.append(fullPath(f), bufferSize, progress);
268   }
269 
270   @Override
rename(final Path src, final Path dst)271   public boolean rename(final Path src, final Path dst) throws IOException {
272     // note fullPath will check that paths are relative to this FileSystem.
273     // Hence both are in same file system and a rename is valid
274     return super.rename(fullPath(src), fullPath(dst));
275   }
276 
277   @Override
setOwner(final Path f, final String username, final String groupname)278   public void setOwner(final Path f, final String username,
279       final String groupname)
280     throws IOException {
281     super.setOwner(fullPath(f), username, groupname);
282   }
283 
284   @Override
setPermission(final Path f, final FsPermission permission)285   public void setPermission(final Path f, final FsPermission permission)
286     throws IOException {
287     super.setPermission(fullPath(f), permission);
288   }
289 
290   @Override
setReplication(final Path f, final short replication)291   public boolean setReplication(final Path f, final short replication)
292     throws IOException {
293     return super.setReplication(fullPath(f), replication);
294   }
295 
296   @Override
setTimes(final Path f, final long mtime, final long atime)297   public void setTimes(final Path f, final long mtime, final long atime)
298       throws IOException {
299     super.setTimes(fullPath(f), mtime, atime);
300   }
301 
302   @Override
modifyAclEntries(Path path, List<AclEntry> aclSpec)303   public void modifyAclEntries(Path path, List<AclEntry> aclSpec)
304       throws IOException {
305     super.modifyAclEntries(fullPath(path), aclSpec);
306   }
307 
308   @Override
removeAclEntries(Path path, List<AclEntry> aclSpec)309   public void removeAclEntries(Path path, List<AclEntry> aclSpec)
310       throws IOException {
311     super.removeAclEntries(fullPath(path), aclSpec);
312   }
313 
314   @Override
removeDefaultAcl(Path path)315   public void removeDefaultAcl(Path path) throws IOException {
316     super.removeDefaultAcl(fullPath(path));
317   }
318 
319   @Override
removeAcl(Path path)320   public void removeAcl(Path path) throws IOException {
321     super.removeAcl(fullPath(path));
322   }
323 
324   @Override
setAcl(Path path, List<AclEntry> aclSpec)325   public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException {
326     super.setAcl(fullPath(path), aclSpec);
327   }
328 
329   @Override
getAclStatus(Path path)330   public AclStatus getAclStatus(Path path) throws IOException {
331     return super.getAclStatus(fullPath(path));
332   }
333 
334   @Override
setXAttr(Path path, String name, byte[] value, EnumSet<XAttrSetFlag> flag)335   public void setXAttr(Path path, String name, byte[] value,
336       EnumSet<XAttrSetFlag> flag) throws IOException {
337     super.setXAttr(fullPath(path), name, value, flag);
338   }
339 
340   @Override
getXAttr(Path path, String name)341   public byte[] getXAttr(Path path, String name) throws IOException {
342     return super.getXAttr(fullPath(path), name);
343   }
344 
345   @Override
getXAttrs(Path path)346   public Map<String, byte[]> getXAttrs(Path path) throws IOException {
347     return super.getXAttrs(fullPath(path));
348   }
349 
350   @Override
getXAttrs(Path path, List<String> names)351   public Map<String, byte[]> getXAttrs(Path path, List<String> names)
352       throws IOException {
353     return super.getXAttrs(fullPath(path), names);
354   }
355 
356   @Override
listXAttrs(Path path)357   public List<String> listXAttrs(Path path) throws IOException {
358     return super.listXAttrs(fullPath(path));
359   }
360 
361   @Override
removeXAttr(Path path, String name)362   public void removeXAttr(Path path, String name) throws IOException {
363     super.removeXAttr(fullPath(path), name);
364   }
365 
366   @Override
resolvePath(final Path p)367   public Path resolvePath(final Path p) throws IOException {
368     return super.resolvePath(fullPath(p));
369   }
370 
371   @Override
getContentSummary(Path f)372   public ContentSummary getContentSummary(Path f) throws IOException {
373     return fs.getContentSummary(fullPath(f));
374   }
375 
376 
377   private static Path rootPath = new Path(Path.SEPARATOR);
378 
379   @Override
getDefaultBlockSize()380   public long getDefaultBlockSize() {
381     return getDefaultBlockSize(fullPath(rootPath));
382   }
383 
384   @Override
getDefaultBlockSize(Path f)385   public long getDefaultBlockSize(Path f) {
386     return super.getDefaultBlockSize(fullPath(f));
387   }
388 
389   @Override
getDefaultReplication()390   public short getDefaultReplication() {
391     return getDefaultReplication(fullPath(rootPath));
392   }
393 
394   @Override
getDefaultReplication(Path f)395   public short getDefaultReplication(Path f) {
396     return super.getDefaultReplication(fullPath(f));
397   }
398 
399   @Override
getServerDefaults()400   public FsServerDefaults getServerDefaults() throws IOException {
401     return getServerDefaults(fullPath(rootPath));
402   }
403 
404   @Override
getServerDefaults(Path f)405   public FsServerDefaults getServerDefaults(Path f) throws IOException {
406     return super.getServerDefaults(fullPath(f));
407   }
408 }
409