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 package info.magnolia.module.files;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.core.HierarchyManager;
38 import info.magnolia.cms.core.NodeData;
39 import info.magnolia.cms.util.ContentUtil;
40 import info.magnolia.cms.util.NodeDataUtil;
41 import org.apache.commons.codec.binary.Hex;
42
43 import javax.jcr.RepositoryException;
44 import java.io.File;
45 import java.io.FileInputStream;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.io.OutputStream;
49 import java.security.DigestInputStream;
50 import java.security.DigestOutputStream;
51 import java.security.MessageDigest;
52 import java.security.NoSuchAlgorithmException;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 class MD5CheckingFileExtractorOperation extends BasicFileExtractorOperation {
68 private final FileExtractionLogger log;
69 private final HierarchyManager hm;
70
71 MD5CheckingFileExtractorOperation(FileExtractionLogger log, HierarchyManager hm, String resourcePath, String absoluteTargetPath) {
72 super(resourcePath, absoluteTargetPath);
73 this.log = log;
74 this.hm = hm;
75 }
76
77 protected InputStream checkInput() throws IOException {
78 return wrap(super.checkInput());
79 }
80
81
82 protected File checkOutput() throws IOException {
83 final File out = super.checkOutput();
84
85 if (out.exists()) {
86
87 final InputStream stream = new FileInputStream(out);
88 final String existingFileMD5 = calculateMD5(stream);
89
90
91 final NodeData repoMD5prop = getRepositoryNode().getNodeData("md5");
92 if (repoMD5prop.isExist()) {
93 final String repoMD5 = repoMD5prop.getString();
94 if (existingFileMD5.equals(repoMD5)) {
95
96 return out;
97 } else {
98 log.error("Can't extract " + resourcePath + " as this file was probably modified locally: expected MD5 [" + repoMD5 + "] but current MD5 is [" + existingFileMD5 + "].");
99 return null;
100 }
101 }
102
103 } else {
104
105 }
106 return out;
107 }
108
109 protected OutputStream openOutput(File outFile) throws IOException {
110 final OutputStream outputStream = super.openOutput(outFile);
111 final MessageDigest md5 = getMessageDigest();
112 return new DigestOutputStream(outputStream, md5);
113 }
114
115 protected void copyAndClose(InputStream in, OutputStream out) throws IOException {
116 super.copyAndClose(in, out);
117
118 final DigestInputStream md5Stream = (DigestInputStream) in;
119 final String newMD5 = retrieveMD5(md5Stream);
120
121 try {
122 NodeDataUtil.getOrCreate(getRepositoryNode(), "md5").setValue(newMD5);
123 } catch (RepositoryException e) {
124 throw new RuntimeException(e);
125 }
126
127 }
128
129 protected Content getRepositoryNode() {
130 try {
131 final String repoPath = getRepositoryPath(resourcePath);
132 final Content node;
133 if (!hm.isExist(repoPath)) {
134 node = ContentUtil.createPath(hm, repoPath);
135 } else {
136 node = hm.getContent(repoPath);
137 }
138 return node;
139 } catch (RepositoryException e) {
140 throw new RuntimeException(e);
141 }
142 }
143
144
145
146
147
148 protected String getRepositoryPath(String resourcePath) {
149 return "/server/install" + resourcePath;
150 }
151
152
153
154
155
156 protected String calculateMD5(InputStream stream) throws IOException {
157 final DigestInputStream md5Stream = wrap(stream);
158 byte[] buffer = new byte[1024];
159 while (md5Stream.read(buffer) != -1) {
160 }
161
162 return retrieveMD5(md5Stream);
163 }
164
165 protected DigestInputStream wrap(InputStream stream) {
166 final MessageDigest md5 = getMessageDigest();
167 return new DigestInputStream(stream, md5);
168 }
169
170 protected String retrieveMD5(DigestInputStream md5Stream) {
171 final byte[] digInBytes = md5Stream.getMessageDigest().digest();
172 return String.valueOf(Hex.encodeHex(digInBytes));
173 }
174
175 protected MessageDigest getMessageDigest() {
176 try {
177 return MessageDigest.getInstance("MD5");
178 } catch (NoSuchAlgorithmException e) {
179 throw new RuntimeException("Can't check files with md5: " + e.getMessage(), e);
180 }
181 }
182 }