Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
CaseNodeData.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2017-2019 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.casemodule.multiusercases;
20
21import java.io.ByteArrayInputStream;
22import java.io.ByteArrayOutputStream;
23import java.io.DataInputStream;
24import java.io.DataOutputStream;
25import java.io.File;
26import java.io.IOException;
27import java.nio.file.Path;
28import java.nio.file.Paths;
29import java.text.ParseException;
30import java.util.Date;
31import java.util.logging.Level;
32import org.sleuthkit.autopsy.casemodule.CaseMetadata;
33import org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException;
34import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
35import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException;
36import org.sleuthkit.autopsy.coreutils.Logger;
37
41public final class CaseNodeData {
42
43 private static final int MAJOR_VERSION = 2;
44 private static final int MINOR_VERSION = 0;
45 private static final Logger logger = Logger.getLogger(CaseNodeData.class.getName());
46
47 /*
48 * Version 0 fields. Note that version 0 node data was only written to the
49 * coordination service node if an auto ingest job error occurred.
50 */
51 private int version;
52 private boolean errorsOccurred;
53
54 /*
55 * Version 1 fields.
56 */
57 private Path directory;
58 private Date createDate;
59 private Date lastAccessDate;
60 private String name;
61 private String displayName;
62 private short deletedItemFlags;
63
64 /*
65 * Version 2 fields.
66 */
67 private int minorVersion;
68
84 public static CaseNodeData createCaseNodeData(final CaseMetadata metadata) throws CaseNodeDataException, InterruptedException {
85 try {
86 final CaseNodeData nodeData = new CaseNodeData(metadata);
88 return nodeData;
89
90 } catch (ParseException | IOException | CoordinationServiceException ex) {
91 throw new CaseNodeDataException(String.format("Error creating case node data for coordination service node with path %s", metadata.getCaseDirectory().toUpperCase()), ex); //NON-NLS
92 }
93 }
94
109 public static CaseNodeData readCaseNodeData(String nodePath) throws CaseNodeDataException, InterruptedException {
110 try {
111 CaseNodeData nodeData;
113 if (nodeBytes != null && nodeBytes.length > 0) {
114 try {
115 nodeData = new CaseNodeData(nodeBytes);
116 } catch (IOException ex) {
117 /*
118 * The existing case node data is corrupted.
119 */
120 logger.log(Level.WARNING, String.format("Error reading node data for coordination service node with path %s, will attempt to replace it", nodePath.toUpperCase()), ex); //NON-NLS
121 final CaseMetadata metadata = getCaseMetadata(nodePath);
122 nodeData = createCaseNodeData(metadata);
123 logger.log(Level.INFO, String.format("Replaced corrupt node data for coordination service node with path %s", nodePath.toUpperCase())); //NON-NLS
124 }
125 } else {
126 /*
127 * The case node data is missing. Version 0 node data was only
128 * written to the coordination service node if an auto ingest
129 * job error occurred.
130 */
131 logger.log(Level.INFO, String.format("Missing node data for coordination service node with path %s, will attempt to create it", nodePath.toUpperCase())); //NON-NLS
132 final CaseMetadata metadata = getCaseMetadata(nodePath);
133 nodeData = createCaseNodeData(metadata);
134 logger.log(Level.INFO, String.format("Created node data for coordination service node with path %s", nodePath.toUpperCase())); //NON-NLS
135 }
136 if (nodeData.getVersion() < CaseNodeData.MAJOR_VERSION) {
137 nodeData = upgradeCaseNodeData(nodePath, nodeData);
138 }
139 return nodeData;
140
141 } catch (CaseNodeDataException | CaseMetadataException | ParseException | IOException | CoordinationServiceException ex) {
142 throw new CaseNodeDataException(String.format("Error reading/writing node data coordination service node with path %s", nodePath.toUpperCase()), ex); //NON-NLS
143 }
144 }
145
158 public static void writeCaseNodeData(CaseNodeData nodeData) throws CaseNodeDataException, InterruptedException {
159 try {
160 CoordinationService.getInstance().setNodeData(CoordinationService.CategoryNode.CASES, nodeData.getDirectory().toString(), nodeData.toArray());
161
162 } catch (IOException | CoordinationServiceException ex) {
163 throw new CaseNodeDataException(String.format("Error writing node data coordination service node with path %s", nodeData.getDirectory().toString().toUpperCase()), ex); //NON-NLS
164 }
165 }
166
180 private static CaseNodeData upgradeCaseNodeData(String nodePath, CaseNodeData oldNodeData) throws CaseNodeDataException, CaseMetadataException, ParseException, IOException, CoordinationServiceException, InterruptedException {
181 CaseNodeData nodeData;
182 switch (oldNodeData.getVersion()) {
183 case 0:
184 /*
185 * Version 0 node data consisted of only the version number and
186 * the errors occurred flag and was only written when an auto
187 * ingest job error occurred. To upgrade from version 0, the
188 * version 1 fields need to be set from the case metadata and
189 * the errors occurred flag needs to be carried forward. Note
190 * that the last accessed date gets advanced to now, since it is
191 * otherwise unknown.
192 */
193 final CaseMetadata metadata = getCaseMetadata(nodePath);
194 nodeData = new CaseNodeData(metadata);
195 nodeData.setErrorsOccurred(oldNodeData.getErrorsOccurred());
196 break;
197 case 1:
198 /*
199 * Version 1 node data did not have a minor version number
200 * field.
201 */
202 oldNodeData.setMinorVersion(MINOR_VERSION);
203 nodeData = oldNodeData;
204 break;
205 default:
206 nodeData = oldNodeData;
207 break;
208 }
209 writeCaseNodeData(nodeData);
210 return nodeData;
211 }
212
226 final Path caseDirectoryPath = Paths.get(nodePath);
227 final File caseDirectory = caseDirectoryPath.toFile();
228 if (!caseDirectory.exists()) {
229 throw new CaseNodeDataException("Case directory does not exist"); // NON-NLS
230 }
231 final Path metadataFilePath = CaseMetadata.getCaseMetadataFilePath(caseDirectoryPath);
232 if (metadataFilePath == null) {
233 throw new CaseNodeDataException("Case meta data file does not exist"); // NON-NLS
234 }
235 return new CaseMetadata(metadataFilePath);
236 }
237
247 private CaseNodeData(CaseMetadata metadata) throws ParseException {
248 this.version = MAJOR_VERSION;
249 this.errorsOccurred = false;
250 this.directory = Paths.get(metadata.getCaseDirectory());
251 this.createDate = CaseMetadata.getDateFormat().parse(metadata.getCreatedDate());
252 this.lastAccessDate = new Date();
253 this.name = metadata.getCaseName();
254 this.displayName = metadata.getCaseDisplayName();
255 this.deletedItemFlags = 0;
256 this.minorVersion = MINOR_VERSION;
257 }
258
267 private CaseNodeData(byte[] nodeData) throws IOException {
268 if (nodeData == null || nodeData.length == 0) {
269 throw new IOException(null == nodeData ? "Null node data byte array" : "Zero-length node data byte array");
270 }
271 try (ByteArrayInputStream byteStream = new ByteArrayInputStream(nodeData); DataInputStream inputStream = new DataInputStream(byteStream)) {
272 this.version = inputStream.readInt();
273 if (this.version == 1) {
274 this.errorsOccurred = inputStream.readBoolean();
275 } else {
276 byte errorsOccurredByte = inputStream.readByte();
277 this.errorsOccurred = (errorsOccurredByte < 0);
278 }
279 if (this.version > 0) {
280 this.directory = Paths.get(inputStream.readUTF());
281 this.createDate = new Date(inputStream.readLong());
282 this.lastAccessDate = new Date(inputStream.readLong());
283 this.name = inputStream.readUTF();
284 this.displayName = inputStream.readUTF();
285 this.deletedItemFlags = inputStream.readShort();
286 }
287 if (this.version > 1) {
288 this.minorVersion = inputStream.readInt();
289 }
290 }
291 }
292
298 private int getVersion() {
299 return this.version;
300 }
301
307 private void setMinorVersion(int minorVersion) {
308 this.minorVersion = minorVersion;
309 }
310
317 public boolean getErrorsOccurred() {
318 return this.errorsOccurred;
319 }
320
327 public void setErrorsOccurred(boolean errorsOccurred) {
328 this.errorsOccurred = errorsOccurred;
329 }
330
336 public Path getDirectory() {
337 return this.directory;
338 }
339
345 public Date getCreateDate() {
346 return new Date(this.createDate.getTime());
347 }
348
354 public Date getLastAccessDate() {
355 return new Date(this.lastAccessDate.getTime());
356 }
357
364 this.lastAccessDate = new Date(lastAccessDate.getTime());
365 }
366
372 public String getName() {
373 return this.name;
374 }
375
381 public String getDisplayName() {
382 return this.displayName;
383 }
384
390 public void setDisplayName(String displayName) {
391 this.displayName = displayName;
392 }
393
401 public boolean isDeletedFlagSet(DeletedFlags flag) {
402 return (this.deletedItemFlags & flag.getValue()) == flag.getValue();
403 }
404
410 public void setDeletedFlag(DeletedFlags flag) {
411 this.deletedItemFlags |= flag.getValue();
412 }
413
423 private byte[] toArray() throws IOException {
424 try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); DataOutputStream outputStream = new DataOutputStream(byteStream)) {
425 outputStream.writeInt(this.version);
426 outputStream.writeByte((byte) (this.errorsOccurred ? 0x80 : 0));
427 outputStream.writeUTF(this.directory.toString());
428 outputStream.writeLong(this.createDate.getTime());
429 outputStream.writeLong(this.lastAccessDate.getTime());
430 outputStream.writeUTF(this.name);
431 outputStream.writeUTF(this.displayName);
432 outputStream.writeShort(this.deletedItemFlags);
433 outputStream.writeInt(this.minorVersion);
434 outputStream.flush();
435 byteStream.flush();
436 return byteStream.toByteArray();
437 }
438 }
439
443 public enum DeletedFlags {
444
450
451 private final short value;
452
458 private DeletedFlags(int value) {
459 this.value = (short) value;
460 }
461
467 private short getValue() {
468 return value;
469 }
470
471 }
472
477 public static final class CaseNodeDataException extends Exception {
478
479 private static final long serialVersionUID = 1L;
480
487 private CaseNodeDataException(String message) {
488 super(message);
489 }
490
498 private CaseNodeDataException(String message, Throwable cause) {
499 super(message, cause);
500 }
501 }
502
503}
static Path getCaseMetadataFilePath(Path directoryPath)
static CaseNodeData createCaseNodeData(final CaseMetadata metadata)
static CaseNodeData upgradeCaseNodeData(String nodePath, CaseNodeData oldNodeData)
void setNodeData(CategoryNode category, String nodePath, byte[] data)
byte[] getNodeData(CategoryNode category, String nodePath)
synchronized static Logger getLogger(String name)
Definition Logger.java:124

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.