/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cassandra.io.util; import java.io.*; import java.text.DecimalFormat; import java.util.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.sun.jna.Native; import org.apache.cassandra.utils.CLibrary; public class FileUtils { private static Logger logger_ = LoggerFactory.getLogger(FileUtils.class); private static final DecimalFormat df_ = new DecimalFormat("#.##"); private static final double kb_ = 1024d; private static final double mb_ = 1024*1024d; private static final double gb_ = 1024*1024*1024d; private static final double tb_ = 1024*1024*1024*1024d; public static void deleteWithConfirm(String file) throws IOException { deleteWithConfirm(new File(file)); } public static void deleteWithConfirm(File file) throws IOException { assert file.exists() : "attempted to delete non-existing file " + file.getName(); if (logger_.isDebugEnabled()) logger_.debug("Deleting " + file.getName()); if (!file.delete()) { throw new IOException("Failed to delete " + file.getAbsolutePath()); } } public static void renameWithConfirm(File from, File to) throws IOException { assert from.exists(); if (logger_.isDebugEnabled()) logger_.debug((String.format("Renaming %s to %s", from.getPath(), to.getPath()))); if (!from.renameTo(to)) throw new IOException(String.format("Failed to rename %s to %s", from.getPath(), to.getPath())); } public static class FileComparator implements Comparator<File> { public int compare(File f, File f2) { return (int)(f.lastModified() - f2.lastModified()); } } public static void createDirectory(String directory) throws IOException { File file = new File(directory); if (!file.exists()) { if (!file.mkdirs()) { throw new IOException("unable to mkdirs " + directory); } } } public static void createFile(String directory) throws IOException { File file = new File(directory); if ( !file.exists() ) file.createNewFile(); } public static boolean isExists(String filename) throws IOException { File file = new File(filename); return file.exists(); } public static boolean delete(String file) { File f = new File(file); return f.delete(); } public static boolean delete(List<String> files) throws IOException { boolean bVal = true; for ( int i = 0; i < files.size(); ++i ) { String file = files.get(i); bVal = delete(file); if (bVal) { if (logger_.isDebugEnabled()) logger_.debug("Deleted file {}", file); files.remove(i); } } return bVal; } public static void delete(File[] files) throws IOException { for ( File file : files ) { file.delete(); } } public static String stringifyFileSize(double value) { double d = 0d; if ( value >= tb_ ) { d = value / tb_; String val = df_.format(d); return val + " TB"; } else if ( value >= gb_ ) { d = value / gb_; String val = df_.format(d); return val + " GB"; } else if ( value >= mb_ ) { d = value / mb_; String val = df_.format(d); return val + " MB"; } else if ( value >= kb_ ) { d = value / kb_; String val = df_.format(d); return val + " KB"; } else { String val = df_.format(value); return val + " bytes"; } } /** * calculate the total space used by a file or directory * * @param path the path * @return total space used. */ public static long getUsedDiskSpaceForPath(String path) { File file = new File(path); if (file.isFile()) { return file.length(); } long diskSpace = 0; for (File childFile: file.listFiles()) { diskSpace += getUsedDiskSpaceForPath(childFile.getPath()); } return diskSpace; } /** * Deletes all files and subdirectories under "dir". * @param dir Directory to be deleted * @throws IOException if any part of the tree cannot be deleted */ public static void deleteRecursive(File dir) throws IOException { if (dir.isDirectory()) { String[] children = dir.list(); for (int i = 0; i < children.length; i++) { deleteRecursive(new File(dir, children[i])); } } // The directory is now empty so now it can be smoked deleteWithConfirm(dir); } /** * Create a hard link for a given file. * * @param sourceFile The name of the source file. * @param destinationFile The name of the destination file. * * @throws IOException if an error has occurred while creating the link. */ public static void createHardLink(File sourceFile, File destinationFile) throws IOException { int errno = Integer.MIN_VALUE; try { int result = CLibrary.link(sourceFile.getAbsolutePath(), destinationFile.getAbsolutePath()); if (result != 0) errno = Native.getLastError(); } catch (UnsatisfiedLinkError e) { createHardLinkWithExec(sourceFile, destinationFile); return; } if (errno != Integer.MIN_VALUE) { // there are 17 different error codes listed on the man page. punt until/unless we find which // ones actually turn up in practice. throw new IOException(String.format("Unable to create hard link from %s to %s (errno %d)", sourceFile, destinationFile, errno)); } } private static void createHardLinkWithExec(File sourceFile, File destinationFile) throws IOException { String osname = System.getProperty("os.name"); ProcessBuilder pb; if (osname.startsWith("Windows")) { float osversion = Float.parseFloat(System.getProperty("os.version")); if (osversion >= 6.0f) { pb = new ProcessBuilder("cmd", "/c", "mklink", "/H", destinationFile.getAbsolutePath(), sourceFile.getAbsolutePath()); } else { pb = new ProcessBuilder("fsutil", "hardlink", "create", destinationFile.getAbsolutePath(), sourceFile.getAbsolutePath()); } } else { pb = new ProcessBuilder("ln", sourceFile.getAbsolutePath(), destinationFile.getAbsolutePath()); pb.redirectErrorStream(true); } Process p = pb.start(); try { p.waitFor(); } catch (InterruptedException e) { throw new RuntimeException(e); } } }