This project has retired. For details please refer to its
Attic page.
ChecksummedFile xref
1 package org.apache.archiva.checksum;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.archiva.common.utils.FileUtils;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 import java.io.FileNotFoundException;
27 import java.io.IOException;
28 import java.nio.charset.Charset;
29 import java.nio.file.Files;
30 import java.nio.file.Path;
31 import java.nio.file.StandardOpenOption;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.List;
35 import java.util.regex.Matcher;
36 import java.util.regex.Pattern;
37
38 import static org.apache.archiva.checksum.ChecksumValidationException.ValidationError.BAD_CHECKSUM_FILE;
39 import static org.apache.archiva.checksum.ChecksumValidationException.ValidationError.BAD_CHECKSUM_FILE_REF;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class ChecksummedFile
55 {
56
57 private static Charset FILE_ENCODING = Charset.forName( "UTF-8" );
58
59 private final Logger log = LoggerFactory.getLogger( ChecksummedFile.class );
60
61 private static final Pattern METADATA_PATTERN = Pattern.compile( "maven-metadata-\\S*.xml" );
62
63 private final Path referenceFile;
64
65
66
67
68
69
70 public ChecksummedFile( final Path referenceFile )
71 {
72 this.referenceFile = referenceFile;
73 }
74
75
76 public static ChecksumReference getFromChecksumFile( Path checksumFile )
77 {
78 ChecksumAlgorithm alg = ChecksumAlgorithm.getByExtension( checksumFile );
79 ChecksummedFilemmedFile.html#ChecksummedFile">ChecksummedFile file = new ChecksummedFile( getReferenceFile( checksumFile ) );
80 return new ChecksumReference( file, alg, checksumFile );
81 }
82
83 private static Path getReferenceFile( Path checksumFile )
84 {
85 String fileName = checksumFile.getFileName( ).toString( );
86 return checksumFile.resolveSibling( fileName.substring( 0, fileName.lastIndexOf( '.' ) ) );
87 }
88
89
90
91
92
93
94
95
96 public String calculateChecksum( ChecksumAlgorithm checksumAlgorithm )
97 throws IOException
98 {
99
100 Checksumksum.html#Checksum">Checksum checksum = new Checksum( checksumAlgorithm );
101 ChecksumUtil.update(checksum, referenceFile );
102 return checksum.getChecksum( );
103 }
104
105
106
107
108
109
110
111
112 public Path writeFile(ChecksumAlgorithm checksumAlgorithm )
113 throws IOException
114 {
115 Path checksumFile = referenceFile.resolveSibling( referenceFile.getFileName( ) + "." + checksumAlgorithm.getDefaultExtension() );
116 Files.deleteIfExists( checksumFile );
117 String checksum = calculateChecksum( checksumAlgorithm );
118 Files.write( checksumFile,
119 ( checksum + " " + referenceFile.getFileName( ).toString( ) ).getBytes( ),
120 StandardOpenOption.CREATE_NEW );
121 return checksumFile;
122 }
123
124
125
126
127
128
129
130
131
132 public Path getChecksumFile( ChecksumAlgorithm checksumAlgorithm )
133 {
134 for ( String ext : checksumAlgorithm.getExt( ) )
135 {
136 Path file = referenceFile.resolveSibling( referenceFile.getFileName( ) + "." + checksumAlgorithm.getExt( ) );
137 if ( Files.exists( file ) )
138 {
139 return file;
140 }
141 }
142 return referenceFile.resolveSibling( referenceFile.getFileName( ) + "." + checksumAlgorithm.getDefaultExtension() );
143 }
144
145
146
147
148
149
150
151
152
153
154
155
156
157 public boolean isValidChecksum( ChecksumAlgorithm algorithm) throws ChecksumValidationException
158 {
159 return isValidChecksum( algorithm, false );
160 }
161 public boolean isValidChecksum( ChecksumAlgorithm algorithm, boolean throwExceptions )
162 throws ChecksumValidationException
163 {
164 return isValidChecksums( Arrays.asList( algorithm ), throwExceptions );
165 }
166
167
168
169
170
171
172
173
174 public boolean isValidChecksums( List<ChecksumAlgorithm> algorithms) throws ChecksumValidationException
175 {
176 return isValidChecksums( algorithms, false );
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195 public boolean isValidChecksums( List<ChecksumAlgorithm> algorithms, boolean throwExceptions) throws ChecksumValidationException
196 {
197
198 List<Checksum> checksums;
199
200 try
201 {
202 checksums = ChecksumUtil.initializeChecksums( referenceFile, algorithms );
203 }
204 catch (IOException e )
205 {
206 log.warn( "Unable to update checksum:{}", e.getMessage( ) );
207 if (throwExceptions) {
208 if (e instanceof FileNotFoundException) {
209 throw new ChecksumValidationException(ChecksumValidationException.ValidationError.FILE_NOT_FOUND, e);
210 } else {
211 throw new ChecksumValidationException(ChecksumValidationException.ValidationError.READ_ERROR, e);
212 }
213 } else {
214 return false;
215 }
216 }
217
218 boolean valid = true;
219 boolean fileExists = false;
220
221
222
223
224
225
226 try
227 {
228
229 for ( Checksum checksum : checksums )
230 {
231 ChecksumAlgorithm checksumAlgorithm = checksum.getAlgorithm( );
232 Path checksumFile = getChecksumFile( checksumAlgorithm );
233
234 if (Files.exists(checksumFile)) {
235 fileExists = true;
236 String expectedChecksum = parseChecksum(checksumFile, checksumAlgorithm, referenceFile.getFileName().toString(), FILE_ENCODING);
237
238 valid &= checksum.compare(expectedChecksum);
239 }
240 }
241 }
242 catch ( ChecksumValidationException e )
243 {
244 log.warn( "Unable to read / parse checksum: {}", e.getMessage( ) );
245 if (throwExceptions) {
246 throw e;
247 } else
248 {
249 return false;
250 }
251 }
252
253 return fileExists && valid;
254 }
255
256 public Path getReferenceFile( )
257 {
258 return referenceFile;
259 }
260
261
262
263 public UpdateStatusList fixChecksum(ChecksumAlgorithm algorithm) {
264 return fixChecksums( Arrays.asList(algorithm) );
265 }
266
267
268
269
270
271
272
273
274 public UpdateStatusList fixChecksums( List<ChecksumAlgorithm> algorithms )
275 {
276 UpdateStatusList result = UpdateStatusList.INITIALIZE(algorithms);
277 List<Checksum> checksums;
278
279
280 try
281 {
282
283 checksums = ChecksumUtil.initializeChecksums(getReferenceFile(), algorithms);
284 }
285 catch (IOException e )
286 {
287 log.warn( e.getMessage( ), e );
288 result.setTotalError(e);
289 return result;
290 }
291
292 if ( checksums.isEmpty( ) )
293 {
294
295 return result;
296 }
297
298 boolean valid = true;
299
300
301 for ( Checksum checksum : checksums )
302 {
303 ChecksumAlgorithm checksumAlgorithm = checksum.getAlgorithm( );
304 try
305 {
306 Path checksumFile = getChecksumFile( checksumAlgorithm );
307 if ( Files.exists( checksumFile ) )
308 {
309 String expectedChecksum;
310 try
311 {
312 expectedChecksum = parseChecksum( checksumFile, checksumAlgorithm, referenceFile.getFileName( ).toString( ), FILE_ENCODING );
313 } catch (ChecksumValidationException ex) {
314 expectedChecksum = "";
315 }
316
317 if ( !checksum.compare( expectedChecksum ) )
318 {
319
320 writeChecksumFile( checksumFile, FILE_ENCODING, checksum.getChecksum( ) );
321 result.setStatus(checksumAlgorithm,UpdateStatus.UPDATED);
322 }
323 }
324 else
325 {
326 writeChecksumFile( checksumFile, FILE_ENCODING, checksum.getChecksum( ) );
327 result.setStatus(checksumAlgorithm, UpdateStatus.CREATED);
328 }
329 }
330 catch ( ChecksumValidationException e )
331 {
332 log.warn( e.getMessage( ), e );
333 result.setErrorStatus(checksumAlgorithm, e);
334 }
335 }
336
337 return result;
338
339 }
340
341 private void writeChecksumFile( Path checksumFile, Charset encoding, String checksumHex )
342 {
343 FileUtils.writeStringToFile( checksumFile, FILE_ENCODING, checksumHex + " " + referenceFile.getFileName( ).toString( ) );
344 }
345
346 private boolean isValidChecksumPattern( String filename, String path )
347 {
348
349
350 Matcher m = METADATA_PATTERN.matcher( path );
351 if ( m.matches( ) )
352 {
353 return filename.endsWith( path ) || ( "-".equals( filename ) ) || filename.endsWith( "maven-metadata.xml" );
354 }
355
356 return filename.endsWith( path ) || ( "-".equals( filename ) );
357 }
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372 public String parseChecksum( Path checksumFile, ChecksumAlgorithm checksumAlgorithm, String fileName, Charset encoding )
373 throws ChecksumValidationException
374 {
375 ChecksumFileContent fc = parseChecksumFile( checksumFile, checksumAlgorithm, encoding );
376 if ( fc.isFormatMatch() && !isValidChecksumPattern( fc.getFileReference( ), fileName ) )
377 {
378 throw new ChecksumValidationException(BAD_CHECKSUM_FILE_REF,
379 "The file reference '" + fc.getFileReference( ) + "' in the checksum file does not match expected file: '" + fileName + "'" );
380 } else if (!fc.isFormatMatch()) {
381 throw new ChecksumValidationException( BAD_CHECKSUM_FILE, "The checksum file content could not be parsed: "+checksumFile );
382 }
383 return fc.getChecksum( );
384
385 }
386 public ChecksumFileContent parseChecksumFile( Path checksumFile, ChecksumAlgorithm checksumAlgorithm, Charset encoding )
387 {
388 ChecksumFileContentileContent.html#ChecksumFileContent">ChecksumFileContent fc = new ChecksumFileContent( );
389 String rawChecksumString = FileUtils.readFileToString( checksumFile, encoding );
390 String trimmedChecksum = rawChecksumString.replace( '\n', ' ' ).trim( );
391
392
393 String regex = checksumAlgorithm.getType( ) + "\\s*\\(([^)]*)\\)\\s*=\\s*([a-fA-F0-9]+)";
394 Matcher m = Pattern.compile( regex ).matcher( trimmedChecksum );
395 if ( m.matches( ) )
396 {
397 fc.setFileReference( m.group( 1 ) );
398 fc.setChecksum( m.group( 2 ) );
399 fc.setFormatMatch( true );
400 }
401 else
402 {
403
404 m = Pattern.compile( "([a-fA-F0-9]+)\\s+\\*?(.+)" ).matcher( trimmedChecksum );
405 if ( m.matches( ) )
406 {
407 fc.setFileReference( m.group( 2 ) );
408 fc.setChecksum( m.group( 1 ) );
409 fc.setFormatMatch( true );
410 }
411 else
412 {
413 fc.setFileReference( "" );
414 fc.setChecksum( trimmedChecksum );
415 fc.setFormatMatch( false );
416 }
417 }
418 return fc;
419 }
420 }