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 @Override
78 protected InputStream checkInput() throws IOException {
79 return wrap(super.checkInput());
80 }
81
82
83 @Override
84 protected File checkOutput() throws IOException {
85 final File out = super.checkOutput();
86
87 if (out.exists()) {
88
89 final InputStream stream = new FileInputStream(out);
90 final String existingFileMD5 = calculateMD5(stream);
91
92
93 final NodeData repoMD5prop = getRepositoryNode().getNodeData("md5");
94 if (repoMD5prop.isExist()) {
95 final String repoMD5 = repoMD5prop.getString();
96 if (existingFileMD5.equals(repoMD5)) {
97
98 return out;
99 }
100 log.error("Can't extract " + resourcePath + " as this file was probably modified locally: expected MD5 [" + repoMD5 + "] but current MD5 is [" + existingFileMD5 + "].");
101 return null;
102 }
103
104 } else {
105
106 }
107 return out;
108 }
109
110 @Override
111 protected OutputStream openOutput(File outFile) throws IOException {
112 final OutputStream outputStream = super.openOutput(outFile);
113 final MessageDigest md5 = getMessageDigest();
114 return new DigestOutputStream(outputStream, md5);
115 }
116
117 @Override
118 protected void copyAndClose(InputStream in, OutputStream out) throws IOException {
119 super.copyAndClose(in, out);
120
121 final DigestInputStream md5Stream = (DigestInputStream) in;
122 final String newMD5 = retrieveMD5(md5Stream);
123
124 try {
125 NodeDataUtil.getOrCreate(getRepositoryNode(), "md5").setValue(newMD5);
126 } catch (RepositoryException e) {
127 throw new RuntimeException(e);
128 }
129
130 }
131
132 protected Content getRepositoryNode() {
133 try {
134 final String repoPath = getRepositoryPath(resourcePath);
135 final Content node;
136 if (!hm.isExist(repoPath)) {
137 node = ContentUtil.createPath(hm, repoPath);
138 } else {
139 node = hm.getContent(repoPath);
140 }
141 return node;
142 } catch (RepositoryException e) {
143 throw new RuntimeException(e);
144 }
145 }
146
147
148
149
150
151 protected String getRepositoryPath(String resourcePath) {
152 return "/server/install" + resourcePath;
153 }
154
155
156
157
158
159 protected String calculateMD5(InputStream stream) throws IOException {
160 final DigestInputStream md5Stream = wrap(stream);
161 byte[] buffer = new byte[1024];
162 while (md5Stream.read(buffer) != -1) {
163 }
164
165 return retrieveMD5(md5Stream);
166 }
167
168 protected DigestInputStream wrap(InputStream stream) {
169 final MessageDigest md5 = getMessageDigest();
170 return new DigestInputStream(stream, md5);
171 }
172
173 protected String retrieveMD5(DigestInputStream md5Stream) {
174 final byte[] digInBytes = md5Stream.getMessageDigest().digest();
175 return String.valueOf(Hex.encodeHex(digInBytes));
176 }
177
178 protected MessageDigest getMessageDigest() {
179 try {
180 return MessageDigest.getInstance("MD5");
181 } catch (NoSuchAlgorithmException e) {
182 throw new RuntimeException("Can't check files with md5: " + e.getMessage(), e);
183 }
184 }
185 }