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 }