Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ public class TemplateLocation {
protected Logger logger = LogManager.getLogger(getClass());
public final static String Filename = "template.properties";

/** Recorded sizes are only trusted when this is disabled; see verifyPhysicalSize(). */
private final static boolean VERIFY_PHYSICAL_SIZE =
Boolean.parseBoolean(System.getProperty("cloudstack.template.verify.physical.size", "true"));

StorageLayer _storage;
String _templatePath;
boolean _isCorrupted;
Expand Down Expand Up @@ -133,6 +137,8 @@ public boolean load() throws IOException {
if (!checkFormatValidity(info)) {
_isCorrupted = true;
logger.warn("Cleaning up inconsistent information for " + format);
} else if (!verifyPhysicalSize(info)) {
_isCorrupted = true;
}
} else {
if (logger.isDebugEnabled()) {
Expand Down Expand Up @@ -225,6 +231,40 @@ protected boolean checkFormatValidity(FormatInfo info) {
return (info.format != null && info.size > 0 && info.virtualSize > 0 && info.filename != null);
}

/**
* Compares the size recorded in the properties file against the actual size of the image on disk.
* <p>
* The recorded {@code <format>.size} is written at download time as {@link StorageLayer#getSize(String)} of the
* image, so the two values are directly comparable. Without this check a truncated or deleted image is still
* reported as a healthy, fully downloaded template, and only fails later when it is copied to primary storage.
*
* @return false if the image is missing or its size does not match the recorded size.
*/
protected boolean verifyPhysicalSize(FormatInfo info) {
if (!VERIFY_PHYSICAL_SIZE) {
return true;
}

String imagePath = _templatePath + info.filename;
if (!_storage.exists(imagePath)) {
logger.warn("Image file '" + imagePath + "' referenced by '" + _file + "' is missing on disk.");
return false;
}

long actualSize = _storage.getSize(imagePath);
if (actualSize != info.size) {
logger.warn("Physical size mismatch for '" + imagePath + "': '" + _file + "' records "
+ toHumanReadableSize(info.size) + " (" + info.size + " bytes) but the file on disk is "
+ toHumanReadableSize(actualSize) + " (" + actualSize + " bytes).");
return false;
}

if (logger.isDebugEnabled()) {
logger.debug("Verified physical size of '" + imagePath + "' as " + toHumanReadableSize(actualSize) + ".");
}
return true;
}

protected FormatInfo deleteFormat(ImageFormat format) {
Iterator<FormatInfo> it = _formats.iterator();
while (it.hasNext()) {
Expand Down