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
019 package org.apache.hadoop.util;
020
021 import java.io.File;
022 import java.io.IOException;
023
024 import org.apache.hadoop.classification.InterfaceAudience;
025 import org.apache.hadoop.classification.InterfaceStability;
026 import org.apache.hadoop.fs.FileStatus;
027 import org.apache.hadoop.fs.LocalFileSystem;
028 import org.apache.hadoop.fs.Path;
029 import org.apache.hadoop.fs.permission.FsAction;
030 import org.apache.hadoop.fs.permission.FsPermission;
031
032 /**
033 * Class that provides utility functions for checking disk problem
034 */
035 @InterfaceAudience.Private
036 @InterfaceStability.Unstable
037 public class DiskChecker {
038
039 public static class DiskErrorException extends IOException {
040 public DiskErrorException(String msg) {
041 super(msg);
042 }
043 }
044
045 public static class DiskOutOfSpaceException extends IOException {
046 public DiskOutOfSpaceException(String msg) {
047 super(msg);
048 }
049 }
050
051 /**
052 * The semantics of mkdirsWithExistsCheck method is different from the mkdirs
053 * method provided in the Sun's java.io.File class in the following way:
054 * While creating the non-existent parent directories, this method checks for
055 * the existence of those directories if the mkdir fails at any point (since
056 * that directory might have just been created by some other process).
057 * If both mkdir() and the exists() check fails for any seemingly
058 * non-existent directory, then we signal an error; Sun's mkdir would signal
059 * an error (return false) if a directory it is attempting to create already
060 * exists or the mkdir fails.
061 * @param dir
062 * @return true on success, false on failure
063 */
064 public static boolean mkdirsWithExistsCheck(File dir) {
065 if (dir.mkdir() || dir.exists()) {
066 return true;
067 }
068 File canonDir = null;
069 try {
070 canonDir = dir.getCanonicalFile();
071 } catch (IOException e) {
072 return false;
073 }
074 String parent = canonDir.getParent();
075 return (parent != null) &&
076 (mkdirsWithExistsCheck(new File(parent)) &&
077 (canonDir.mkdir() || canonDir.exists()));
078 }
079
080 /**
081 * Create the directory if it doesn't exist and check that dir is readable,
082 * writable and executable
083 *
084 * @param dir
085 * @throws DiskErrorException
086 */
087 public static void checkDir(File dir) throws DiskErrorException {
088 if (!mkdirsWithExistsCheck(dir))
089 throw new DiskErrorException("Can not create directory: "
090 + dir.toString());
091
092 if (!dir.isDirectory())
093 throw new DiskErrorException("Not a directory: "
094 + dir.toString());
095
096 if (!dir.canRead())
097 throw new DiskErrorException("Directory is not readable: "
098 + dir.toString());
099
100 if (!dir.canWrite())
101 throw new DiskErrorException("Directory is not writable: "
102 + dir.toString());
103
104 if (!dir.canExecute())
105 throw new DiskErrorException("Directory is not executable: "
106 + dir.toString());
107 }
108
109 /**
110 * Create the directory or check permissions if it already exists.
111 *
112 * The semantics of mkdirsWithExistsAndPermissionCheck method is different
113 * from the mkdirs method provided in the Sun's java.io.File class in the
114 * following way:
115 * While creating the non-existent parent directories, this method checks for
116 * the existence of those directories if the mkdir fails at any point (since
117 * that directory might have just been created by some other process).
118 * If both mkdir() and the exists() check fails for any seemingly
119 * non-existent directory, then we signal an error; Sun's mkdir would signal
120 * an error (return false) if a directory it is attempting to create already
121 * exists or the mkdir fails.
122 *
123 * @param localFS local filesystem
124 * @param dir directory to be created or checked
125 * @param expected expected permission
126 * @throws IOException
127 */
128 public static void mkdirsWithExistsAndPermissionCheck(
129 LocalFileSystem localFS, Path dir, FsPermission expected)
130 throws IOException {
131 File directory = localFS.pathToFile(dir);
132 boolean created = false;
133
134 if (!directory.exists())
135 created = mkdirsWithExistsCheck(directory);
136
137 if (created || !localFS.getFileStatus(dir).getPermission().equals(expected))
138 localFS.setPermission(dir, expected);
139 }
140
141 /**
142 * Create the local directory if necessary, check permissions and also ensure
143 * it can be read from and written into.
144 *
145 * @param localFS local filesystem
146 * @param dir directory
147 * @param expected permission
148 * @throws DiskErrorException
149 * @throws IOException
150 */
151 public static void checkDir(LocalFileSystem localFS, Path dir,
152 FsPermission expected)
153 throws DiskErrorException, IOException {
154 mkdirsWithExistsAndPermissionCheck(localFS, dir, expected);
155
156 FileStatus stat = localFS.getFileStatus(dir);
157 FsPermission actual = stat.getPermission();
158
159 if (!stat.isDirectory())
160 throw new DiskErrorException("not a directory: "+ dir.toString());
161
162 FsAction user = actual.getUserAction();
163 if (!user.implies(FsAction.READ))
164 throw new DiskErrorException("directory is not readable: "
165 + dir.toString());
166
167 if (!user.implies(FsAction.WRITE))
168 throw new DiskErrorException("directory is not writable: "
169 + dir.toString());
170
171 if (!user.implies(FsAction.EXECUTE))
172 throw new DiskErrorException("directory is not listable: "
173 + dir.toString());
174 }
175 }