1 /*
2  * Sleuth Kit Data Model
3  *
4  * Copyright 2011-2016 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  */
19 package org.sleuthkit.datamodel;
20 
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Set;
26 import java.util.logging.Level;
27 import java.util.logging.Logger;
28 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
29 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
30 import org.sleuthkit.datamodel.SleuthkitCase.ObjectInfo;
31 
32 /**
33  * Implements some general methods from the Content interface common across many
34  * content sub types
35  */
36 public abstract class AbstractContent implements Content {
37 
38 	public final static long UNKNOWN_ID = -1;
39 	private final SleuthkitCase db;
40 	private final long objId;
41 	private final String name;
42 	private Content parent;
43 	private String uniquePath;
44 	protected long parentId;
45 	private volatile boolean hasChildren;
46 	private volatile boolean checkedHasChildren;
47 	private volatile int childrenCount;
48 	private BlackboardArtifact genInfoArtifact = null;
49 
AbstractContent(SleuthkitCase db, long obj_id, String name)50 	protected AbstractContent(SleuthkitCase db, long obj_id, String name) {
51 		this.db = db;
52 		this.objId = obj_id;
53 		this.name = name;
54 		this.parentId = UNKNOWN_ID;
55 
56 		checkedHasChildren = false;
57 		hasChildren = false;
58 		childrenCount = -1;
59 	}
60 
61 	@Override
getName()62 	public String getName() {
63 		return this.name;
64 	}
65 
66 	/*
67 	 * This base implementation simply walks the hierarchy appending its own
68 	 * name to the result of calling its parent's getUniquePath() method (with
69 	 * interleaving forward slashes).
70 	 */
71 	@Override
getUniquePath()72 	public synchronized String getUniquePath() throws TskCoreException {
73 		if (uniquePath == null) {
74 			uniquePath = "";
75 			if (!name.isEmpty()) {
76 				uniquePath = "/" + getName();
77 			}
78 
79 			Content myParent = getParent();
80 			if (myParent != null) {
81 				uniquePath = myParent.getUniquePath() + uniquePath;
82 			}
83 		}
84 		return uniquePath;
85 	}
86 
87 	@Override
hasChildren()88 	public boolean hasChildren() throws TskCoreException {
89 		if (checkedHasChildren == true) {
90 			return hasChildren;
91 		}
92 
93 		hasChildren = this.getSleuthkitCase().getHasChildren(this);
94 		checkedHasChildren = true;
95 
96 		return hasChildren;
97 	}
98 
99 	@Override
getChildrenCount()100 	public int getChildrenCount() throws TskCoreException {
101 		if (childrenCount != -1) {
102 			return childrenCount;
103 		}
104 
105 		childrenCount = this.getSleuthkitCase().getContentChildrenCount(this);
106 
107 		hasChildren = childrenCount > 0;
108 		checkedHasChildren = true;
109 
110 		return childrenCount;
111 	}
112 
113 	@Override
getParent()114 	public synchronized Content getParent() throws TskCoreException {
115 		if (parent == null) {
116 			ObjectInfo parentInfo;
117 			parentInfo = db.getParentInfo(this);
118 			if (parentInfo == null) {
119 				parent = null;
120 			} else {
121 				parent = db.getContentById(parentInfo.getId());
122 			}
123 		}
124 		return parent;
125 	}
126 
setParent(Content parent)127 	void setParent(Content parent) {
128 		this.parent = parent;
129 	}
130 
131 	/**
132 	 * Set the ID of the this AbstractContent's parent
133 	 *
134 	 * @param parentId the ID of the parent. Note: use
135 	 *                 AbstractContent.UNKNOWN_ID if the parent's ID is not
136 	 *                 known.
137 	 */
setParentId(long parentId)138 	void setParentId(long parentId) {
139 		this.parentId = parentId;
140 	}
141 
142 	@Override
getId()143 	public long getId() {
144 		return this.objId;
145 	}
146 
147 	/**
148 	 * Gets all children of this abstract content, if any.
149 	 *
150 	 * @return A list of the children.
151 	 *
152 	 * @throws TskCoreException if there was an error querying the case
153 	 *                          database.
154 	 */
155 	@Override
getChildren()156 	public List<Content> getChildren() throws TskCoreException {
157 		List<Content> children = new ArrayList<Content>();
158 
159 		children.addAll(getSleuthkitCase().getAbstractFileChildren(this));
160 		children.addAll(getSleuthkitCase().getBlackboardArtifactChildren(this));
161 
162 		return children;
163 
164 	}
165 
166 	/**
167 	 * Gets the object ids of objects, if any, that are children of this
168 	 * abstract content.
169 	 *
170 	 * @return A list of the object ids.
171 	 *
172 	 * @throws TskCoreException if there was an error querying the case
173 	 *                          database.
174 	 */
175 	@Override
getChildrenIds()176 	public List<Long> getChildrenIds() throws TskCoreException {
177 
178 		List<Long> childrenIDs = new ArrayList<Long>();
179 
180 		childrenIDs.addAll(getSleuthkitCase().getAbstractFileChildrenIds(this));
181 		childrenIDs.addAll(getSleuthkitCase().getBlackboardArtifactChildrenIds(this));
182 
183 		return childrenIDs;
184 	}
185 
186 	// classes should override this if they can be a data source
187 	@Override
getDataSource()188 	public Content getDataSource() throws TskCoreException {
189 		Content myParent = getParent();
190 		if (myParent == null) {
191 			return null;
192 		}
193 
194 		return myParent.getDataSource();
195 	}
196 
197 	/**
198 	 * Gets handle of SleuthkitCase to which this content belongs
199 	 *
200 	 * @return the case handle
201 	 */
getSleuthkitCase()202 	public SleuthkitCase getSleuthkitCase() {
203 		return db;
204 	}
205 
206 	@Override
equals(Object obj)207 	public boolean equals(Object obj) {
208 		if (obj == null) {
209 			return false;
210 		}
211 		if (getClass() != obj.getClass()) {
212 			return false;
213 		}
214 		final AbstractContent other = (AbstractContent) obj;
215 		if (this.objId != other.objId) {
216 			return false;
217 		}
218 
219 		try {
220 			// New children may have been added to an existing content
221 			// object in which case they are not equal.
222 			if (this.getChildrenCount() != other.getChildrenCount()) {
223 				return false;
224 			}
225 		} catch (TskCoreException ex) {
226 			Logger.getLogger(AbstractContent.class.getName()).log(Level.SEVERE, null, ex);
227 		}
228 
229 		return true;
230 	}
231 
232 	@Override
hashCode()233 	public int hashCode() {
234 		int hash = 7 + (int) (this.objId ^ (this.objId >>> 32));
235 		try {
236 			hash = 41 * hash + this.getChildrenCount();
237 		} catch (TskCoreException ex) {
238 			Logger.getLogger(AbstractContent.class.getName()).log(Level.SEVERE, null, ex);
239 		}
240 		return hash;
241 	}
242 
243 	@Override
newArtifact(int artifactTypeID)244 	public BlackboardArtifact newArtifact(int artifactTypeID) throws TskCoreException {
245 		// don't let them make more than 1 GEN_INFO
246 		if (artifactTypeID == ARTIFACT_TYPE.TSK_GEN_INFO.getTypeID()) {
247 			return getGenInfoArtifact(true);
248 		}
249 		return db.newBlackboardArtifact(artifactTypeID, objId);
250 	}
251 
252 	@Override
newArtifact(BlackboardArtifact.ARTIFACT_TYPE type)253 	public BlackboardArtifact newArtifact(BlackboardArtifact.ARTIFACT_TYPE type) throws TskCoreException {
254 		return newArtifact(type.getTypeID());
255 	}
256 
257 	@Override
getArtifacts(String artifactTypeName)258 	public ArrayList<BlackboardArtifact> getArtifacts(String artifactTypeName) throws TskCoreException {
259 		return getArtifacts(db.getArtifactType(artifactTypeName).getTypeID());
260 	}
261 
262 	@Override
getArtifacts(int artifactTypeID)263 	public ArrayList<BlackboardArtifact> getArtifacts(int artifactTypeID) throws TskCoreException {
264 		if (artifactTypeID == ARTIFACT_TYPE.TSK_GEN_INFO.getTypeID()) {
265 			if (genInfoArtifact == null) // don't make one if it doesn't already exist
266 			{
267 				getGenInfoArtifact(false);
268 			}
269 
270 			ArrayList<BlackboardArtifact> list = new ArrayList<BlackboardArtifact>();
271 			// genInfoArtifact coudl still be null if there isn't an artifact
272 			if (genInfoArtifact != null) {
273 				list.add(genInfoArtifact);
274 			}
275 			return list;
276 		}
277 		return db.getBlackboardArtifacts(artifactTypeID, objId);
278 	}
279 
280 	@Override
getArtifacts(BlackboardArtifact.ARTIFACT_TYPE type)281 	public ArrayList<BlackboardArtifact> getArtifacts(BlackboardArtifact.ARTIFACT_TYPE type) throws TskCoreException {
282 		return getArtifacts(type.getTypeID());
283 	}
284 
285 	@Override
getGenInfoArtifact()286 	public BlackboardArtifact getGenInfoArtifact() throws TskCoreException {
287 		return getGenInfoArtifact(true);
288 	}
289 
290 	@Override
getGenInfoArtifact(boolean create)291 	public BlackboardArtifact getGenInfoArtifact(boolean create) throws TskCoreException {
292 		if (genInfoArtifact != null) {
293 			return genInfoArtifact;
294 		}
295 
296 		// go to db directly to avoid infinite loop
297 		ArrayList<BlackboardArtifact> arts = db.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO, objId);
298 		BlackboardArtifact retArt;
299 		if (arts.isEmpty()) {
300 			if (create) {
301 				retArt = db.newBlackboardArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO, objId);
302 			} else {
303 				return null;
304 			}
305 		} else {
306 			retArt = arts.get(0);
307 		}
308 		genInfoArtifact = retArt;
309 		return retArt;
310 	}
311 
312 	@Override
getGenInfoAttributes(ATTRIBUTE_TYPE attr_type)313 	public ArrayList<BlackboardAttribute> getGenInfoAttributes(ATTRIBUTE_TYPE attr_type) throws TskCoreException {
314 		ArrayList<BlackboardAttribute> returnList = new ArrayList<BlackboardAttribute>();
315 
316 		if (genInfoArtifact == null) {
317 			getGenInfoArtifact(false);
318 			if (genInfoArtifact == null) {
319 				return returnList;
320 			}
321 		}
322 
323 		for (BlackboardAttribute attribute : genInfoArtifact.getAttributes()) {
324 			if (attribute.getAttributeType().getTypeID() == attr_type.getTypeID()) {
325 				returnList.add(attribute);
326 			}
327 		}
328 
329 		return returnList;
330 	}
331 
332 	@Override
getAllArtifacts()333 	public ArrayList<BlackboardArtifact> getAllArtifacts() throws TskCoreException {
334 		return db.getMatchingArtifacts("WHERE obj_id = " + objId); //NON-NLS
335 	}
336 
337 	@Override
getArtifactsCount(String artifactTypeName)338 	public long getArtifactsCount(String artifactTypeName) throws TskCoreException {
339 		return db.getBlackboardArtifactsCount(artifactTypeName, objId);
340 	}
341 
342 	@Override
getArtifactsCount(int artifactTypeID)343 	public long getArtifactsCount(int artifactTypeID) throws TskCoreException {
344 		return db.getBlackboardArtifactsCount(artifactTypeID, objId);
345 	}
346 
347 	@Override
getArtifactsCount(ARTIFACT_TYPE type)348 	public long getArtifactsCount(ARTIFACT_TYPE type) throws TskCoreException {
349 		return db.getBlackboardArtifactsCount(type, objId);
350 	}
351 
352 	@Override
getAllArtifactsCount()353 	public long getAllArtifactsCount() throws TskCoreException {
354 		return db.getBlackboardArtifactsCount(objId);
355 	}
356 
357 	@Override
getHashSetNames()358 	public Set<String> getHashSetNames() throws TskCoreException {
359 		Set<String> hashNames = new HashSet<String>();
360 		ArrayList<BlackboardArtifact> artifacts = getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT);
361 
362 		for (BlackboardArtifact a : artifacts) {
363 			BlackboardAttribute attribute = a.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME));
364 			if (attribute != null) {
365 				hashNames.add(attribute.getValueString());
366 			}
367 		}
368 		return Collections.unmodifiableSet(hashNames);
369 	}
370 
371 	@Override
toString()372 	public String toString() {
373 		return toString(true);
374 	}
375 
toString(boolean preserveState)376 	public String toString(boolean preserveState) {
377 		if (preserveState) {
378 			return "AbstractContent [\t" + "objId " + String.format("%010d", objId) + "\t" //NON-NLS
379 					+ "name " + name + "\t" + "parentId " + parentId + "\t" //NON-NLS
380 					+ "\t" + "checkedHasChildren " + checkedHasChildren //NON-NLS
381 					+ "\t" + "hasChildren " + hasChildren //NON-NLS
382 					+ "\t" + "childrenCount " + childrenCount //NON-NLS
383 					+ "uniquePath " + uniquePath + "]\t"; //NON-NLS
384 		} else {
385 			try {
386 				if (getParent() != null) {
387 					return "AbstractContent [\t" + "objId " + String.format("%010d", objId) //NON-NLS
388 							+ "\t" + "name " + name //NON-NLS
389 							+ "\t" + "checkedHasChildren " + checkedHasChildren //NON-NLS
390 							+ "\t" + "hasChildren " + hasChildren //NON-NLS
391 							+ "\t" + "childrenCount " + childrenCount //NON-NLS
392 							+ "\t" + "getUniquePath " + getUniquePath() //NON-NLS
393 							+ "\t" + "getParent " + getParent().getId() + "]\t"; //NON-NLS
394 				} else {
395 					return "AbstractContent [\t" + "objId " //NON-NLS
396 							+ String.format("%010d", objId) + "\t" + "name " + name //NON-NLS
397 							+ "\t" + "checkedHasChildren " + checkedHasChildren //NON-NLS
398 							+ "\t" + "hasChildren " + hasChildren //NON-NLS
399 							+ "\t" + "childrenCount " + childrenCount //NON-NLS
400 							+ "\t" + "uniquePath " + getUniquePath() //NON-NLS
401 							+ "\t" + "parentId " + parentId + "]\t"; //NON-NLS
402 				}
403 			} catch (TskCoreException ex) {
404 				Logger.getLogger(AbstractContent.class.getName()).log(Level.SEVERE, "Could not find Parent", ex); //NON-NLS
405 				return "AbstractContent [\t" + "objId " + String.format("%010d", objId) + "\t" //NON-NLS
406 						+ "name " + name + "\t" + "parentId " + parentId + "\t" //NON-NLS
407 						+ "\t" + "checkedHasChildren " + checkedHasChildren //NON-NLS
408 						+ "\t" + "hasChildren " + hasChildren //NON-NLS
409 						+ "\t" + "childrenCount " + childrenCount //NON-NLS
410 						+ "uniquePath " + uniquePath + "]\t";  //NON-NLS
411 			}
412 		}
413 	}
414 }
415