summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx/imagemaster/crcchecker/CRCChecker.java
blob: 1baa99491ba16caed250d9028630e0ea0cad57f4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package org.openslx.imagemaster.crcchecker;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.CRC32;

import org.apache.log4j.Logger;
import org.openslx.imagemaster.Globals;

// TODO: Move to master-sync-shared, sattelite daemon might want to check images too

public class CRCChecker
{
	
	private static Logger log = Logger.getLogger( CRCChecker.class );
	
	/**
	 * Checks the CRC sum of given blocks of a given imageFile against a given crcFile. 
	 * @param imageFile The imageFile to check
	 * @param crcFile The crcFile to check against
	 * @param blocks The blocks to check
	 * @return List of blocks where the crc matches, or null if the crc file is corrupted
	 */
	public static List<Integer> checkCRC(String imageFile, String crcFile, List<Integer> blocks) throws IOException
	{
		List<Integer> result = new LinkedList<>();
		
		ImageFile image = new ImageFile( imageFile, Globals.blockSize );
		CRCFile crc = new CRCFile( crcFile );
		
		log.debug( "Checking image file: '" + imageFile + "' with crc file: '" + crcFile + "'");
		try {
			if (!crc.isValid()) return null;
			// TODO: also return null if the crc file contains the wrong number of checksums (only makes sense if the upload is complete)
		} catch (IOException e) {
			throw new IOException( "Could not read CRC file", e );
		}
		
		// file is smaller than one block - no need to check crc yet
		// TODO: Needs more logic, if the image is complete and < 16MB, we still need to check the block.
		// The caller should make sure to only check crc of blocks that are finished downloading
		if (image.length() < Globals.blockSize) {
			return result;
		}
		// check all blocks
		for (Integer blockN : blocks) {
			byte[] block;
			try {
				// TODO: For performance improvements maybe prealloc the array outside the loop with a size of Globals.BLOCK_SIZE
				// and then make getBlock(blockN, block) return the actual size of the block (Should always be BLOCK_SIZE except
				// for the last block), so you never need to create fresh byte arrays inside the loop
				block = image.getBlock( blockN );
			} catch ( IOException e ) {
				throw new IOException( "Could not read image file", e );
			}
			
			if (block == null) continue; // some error occured (for example: someone tried to check a block that is not in the file)
			
			// check this block with CRC32
			// add this block to result, if check was ok with CRC file
			
			CRC32 crcCalc = new CRC32();
			crcCalc.update( block );
			int crcSum = Integer.reverseBytes( (int) crcCalc.getValue() );
			int crcSumFromFile;
			try {
				crcSumFromFile = crc.getCRCSum( blockN );
			} catch ( IOException e ) {
				throw new IOException( "Could not read CRC file", e );
			}
			
			if (crcSum == crcSumFromFile) result.add( blockN );
			else log.debug(blockN + " was invalid");
		}
		
		return result;
	}
}