package org.openslx.bwlp.sat.util;
import java.io.File;
import org.apache.commons.io.FilenameUtils;
import org.apache.log4j.Logger;
import org.openslx.bwlp.sat.database.models.LocalImageVersion;
import org.openslx.util.QuickTimer;
import org.openslx.util.QuickTimer.Task;
public class FileSystem {
private static final Logger LOGGER = Logger.getLogger(FileSystem.class);
public static String getRelativePath(File absolutePath, File parentDir) {
String file;
String dir;
try {
file = absolutePath.getCanonicalPath();
dir = parentDir.getCanonicalPath() + File.separator;
} catch (Exception e) {
LOGGER.error("Could not get relative path for " + absolutePath.toString(), e);
return null;
}
if (!file.startsWith(dir))
return null;
return file.substring(dir.length());
}
/**
* Delete given file on the {@link QuickTimer} thread, preventing the
* calling thread from freezing/hanging on I/O problems.
*
* @param sourceCandidates the file to delete
*/
public static void deleteAsync(final File... files) {
if (files == null || files.length == 0)
return;
QuickTimer.scheduleOnce(new Task() {
@Override
public void fire() {
for (File file : files) {
if (file == null)
continue;
if (!file.exists()) {
continue;
}
if (!file.delete()) {
LOGGER.warn("Could not delete file " + file.getAbsolutePath());
}
}
}
});
}
/**
* Checks if the VM store is mounted.
*
* @return true if mounted, false otherwise.
*/
public static boolean isStorageMounted() {
File flagFile = new File(Configuration.getVmStoreBasePath(), ".notmounted");
if (flagFile.exists())
return false;
File prodPath = Configuration.getVmStoreProdPath();
if (prodPath.isDirectory())
return true;
return prodPath.mkdir();
}
private static Object storageMutex = new Object();
public static boolean waitForStorage() {
if (isStorageMounted())
return true;
synchronized (storageMutex) {
if (isStorageMounted())
return true;
LOGGER.warn("VM storage gone, waiting for it to reappear...");
long lastComplain = System.currentTimeMillis();
do {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
LOGGER.warn("Interrupted while waiting", e);
return false;
}
if (System.currentTimeMillis() - lastComplain > 600000) {
lastComplain = System.currentTimeMillis();
LOGGER.warn("Still waiting for storage...");
}
} while (!isStorageMounted());
}
LOGGER.info("VM storage back online");
return true;
}
/**
* Delete the given image file (and all related files) from the storage.
*
* @param image The image to be deleted
*/
public static void deleteImageRelatedFiles(LocalImageVersion image) {
File imageFile = composeAbsoluteImagePath(image);
if (imageFile == null)
return;
File metaFile = new File(imageFile.getPath() + ".meta");
File crcFile = new File(imageFile.getPath() + ".crc");
File mapFile = new File(imageFile.getPath() + ".map");
if (!waitForStorage())
return;
deleteAsync(imageFile, metaFile, crcFile, mapFile);
}
/**
* Given a local image version, return a {@link File} object that holds the
* full path to the image file in the file system.
*
* @param localImageData
* @return {@link File} representing the physical image file, or
* null
if the path would not be valid
*/
public static File composeAbsoluteImagePath(LocalImageVersion localImageData) {
if (localImageData == null)
return null;
File path = composeAbsolutePath(localImageData.filePath);
if (path == null) {
LOGGER.warn("ImageVersionId is " + localImageData.imageVersionId);
}
return path;
}
/**
* Given a local relative path for an image, return a {@link File} object
* that holds the full path to the image file in the file system.
*
* @param relativePath
* @return {@link File} representing the physical image file, or
* null
if the path would not be valid
*/
public static File composeAbsolutePath(String relativePath) {
if (relativePath != null) {
relativePath = FilenameUtils.normalize(relativePath);
}
if (relativePath == null || relativePath.startsWith("/")) {
LOGGER.warn("Invalid path for local image: " + relativePath);
return null;
}
return new File(Configuration.getVmStoreBasePath(), relativePath);
}
private static long lastStorageFailLog = 0;
/**
* Query how much space is left in the vmstore directory.
*
* @return free space in vmstore directory, in bytes, or -1 on error
*/
public static long getAvailableStorageBytes() {
if (!isStorageMounted())
return -1;
try {
return Configuration.getVmStoreProdPath().getUsableSpace();
} catch (Exception e) {
long now = System.currentTimeMillis();
if (now - lastStorageFailLog > 60000) {
lastStorageFailLog = now;
LOGGER.warn("Could not determine free space of vmstore", e);
}
return -1;
}
}
}