Sleuth Kit Java Bindings (JNI) 4.14.0
Java bindings for using The Sleuth Kit
Loading...
Searching...
No Matches
AbstractFile.java
Go to the documentation of this file.
1/*
2 * SleuthKit Java Bindings
3 *
4 * Copyright 2011-2022 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.datamodel;
20
21import com.google.common.annotations.Beta;
22import java.io.FileNotFoundException;
23import java.io.IOException;
24import java.io.RandomAccessFile;
25import java.lang.ref.SoftReference;
26import java.sql.SQLException;
27import java.sql.Statement;
28import java.text.MessageFormat;
29import java.util.ArrayList;
30import java.util.Collection;
31import java.util.Collections;
32import java.util.List;
33import java.util.Objects;
34import java.util.Optional;
35import java.util.ResourceBundle;
36import java.util.Set;
37import java.util.SortedSet;
38import java.util.TimeZone;
39import java.util.logging.Level;
40import java.util.logging.Logger;
41import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
42import org.sleuthkit.datamodel.TskData.CollectedStatus;
43import org.sleuthkit.datamodel.TskData.FileKnown;
44import org.sleuthkit.datamodel.TskData.TSK_FS_META_FLAG_ENUM;
45import org.sleuthkit.datamodel.TskData.TSK_FS_META_TYPE_ENUM;
46import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
47import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_TYPE_ENUM;
48
53public abstract class AbstractFile extends AbstractContent {
54
59 protected Set<TSK_FS_META_FLAG_ENUM> metaFlags;
60 protected final Long fileSystemObjectId; // File system object ID; may be null
61 protected long size;
62 protected final long metaAddr, ctime, crtime, atime, mtime;
63 protected final int metaSeq;
64 protected final int uid, gid;
65 protected final int attrId;
67 protected final Set<TskData.TSK_FS_META_MODE_ENUM> modes;
68 //local file support
69 private boolean localPathSet = false;
70 private String localPath;
71 private String localAbsPath;
72 private volatile RandomAccessFile localFileHandle;
73 private volatile java.io.File localFile;
74 private TskData.EncodingType encodingType;
75 //range support
76 private List<TskFileRange> ranges;
77 /*
78 * path of parent directory
79 */
80 protected final String parentPath;
85 private boolean knownStateDirty = false;
86 /*
87 * md5 hash
88 */
89 protected String md5Hash;
90 private boolean md5HashDirty = false;
91 /*
92 * SHA-256 hash
93 */
94 protected String sha256Hash;
95 private boolean sha256HashDirty = false;
96
97 /*
98 * SHA-1 hash
99 */
100 protected String sha1Hash;
101 private boolean sha1HashDirty = false;
102
103 private TskData.CollectedStatus collected; // Collected status of file data
104 private boolean collectedDirty = false;
105
106 private String mimeType;
107 private boolean mimeTypeDirty = false;
108 private static final Logger LOGGER = Logger.getLogger(AbstractFile.class.getName());
109 private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle");
110 private long dataSourceObjectId;
111 private final String extension;
112 private final List<Attribute> fileAttributesCache = new ArrayList<Attribute>();
113 private boolean loadedAttributesCacheFromDb = false;
114
115 private final String ownerUid; // string owner uid, for example a Windows SID.
116 // different from the numeric uid which is more commonly found
117 // on Unix based file systems.
118 private final Long osAccountObjId; // obj id of the owner's OS account, may be null
119
120 private volatile String uniquePath;
121 private volatile FileSystem parentFileSystem;
122
123 private final boolean tryContentProviderStream;
124 private Object contentProviderStreamLock = new Object();
125 private SoftReference<ContentProviderStream> contentProviderStreamRef = null;
126
168 AbstractFile(SleuthkitCase db,
169 long objId,
170 long dataSourceObjectId,
173 String name,
175 long metaAddr, int metaSeq,
178 long size,
179 long ctime, long crtime, long atime, long mtime,
180 short modes,
181 int uid, int gid,
182 String md5Hash, String sha256Hash, String sha1Hash,
184 String parentPath,
185 String mimeType,
186 String extension,
187 String ownerUid,
188 Long osAccountObjectId,
189 TskData.CollectedStatus collected,
190 List<Attribute> fileAttributes) {
191 super(db, objId, name);
192 this.dataSourceObjectId = dataSourceObjectId;
193 if (fileSystemObjectId != null) {
194 // When reading from the result set, nulls are converted to zeros.
195 // Switch it to null.
196 if (fileSystemObjectId > 0) {
197 this.fileSystemObjectId = fileSystemObjectId;
198 } else {
199 this.fileSystemObjectId = null;
200 }
201 } else {
202 this.fileSystemObjectId = null;
203 }
204 this.attrType = attrType;
205 this.attrId = attrId;
206 this.fileType = fileType;
207 this.metaAddr = metaAddr;
208 this.metaSeq = metaSeq;
209 this.dirType = dirType;
210 this.metaType = metaType;
211 this.dirFlag = dirFlag;
212 this.metaFlags = TSK_FS_META_FLAG_ENUM.valuesOf(metaFlags);
213 this.size = size;
214 this.ctime = ctime;
215 this.crtime = crtime;
216 this.atime = atime;
217 this.mtime = mtime;
218 this.uid = uid;
219 this.gid = gid;
220 this.modes = TskData.TSK_FS_META_MODE_ENUM.valuesOf(modes);
221
222 this.md5Hash = md5Hash;
223 this.sha256Hash = sha256Hash;
224 this.sha1Hash = sha1Hash;
225 if (knownState == null) {
226 this.knownState = FileKnown.UNKNOWN;
227 } else {
228 this.knownState = knownState;
229 }
230 this.parentPath = parentPath;
231 this.mimeType = mimeType;
232 this.extension = extension == null ? "" : extension;
233 this.encodingType = TskData.EncodingType.NONE;
234 this.ownerUid = ownerUid;
235 this.osAccountObjId = osAccountObjectId;
236 this.collected = collected;
237 // any item that is marked as YES_REPO and there is a custom content provider for the db will attempt to use the content provider to provide data
238 // this will be flipped to false if there is no content provider stream from the content provider for this file
239 this.tryContentProviderStream = collected == CollectedStatus.YES_REPO && db.getContentProvider() != null;
240 if (Objects.nonNull(fileAttributes) && !fileAttributes.isEmpty()) {
241 this.fileAttributesCache.addAll(fileAttributes);
242 loadedAttributesCacheFromDb = true;
243 }
244 }
245
252 return fileType;
253 }
254
263
269 public int getAttributeId() {
270 return attrId;
271 }
272
278 public long getCtime() {
279 return ctime;
280 }
281
287 public String getCtimeAsDate() {
288 return epochToTime(ctime);
289 }
290
296 public long getCrtime() {
297 return crtime;
298 }
299
305 public String getCrtimeAsDate() {
306 return epochToTime(crtime);
307 }
308
314 public long getAtime() {
315 return atime;
316 }
317
323 public String getAtimeAsDate() {
324 return epochToTime(atime);
325 }
326
332 public long getMtime() {
333 return mtime;
334 }
335
341 public String getMtimeAsDate() {
342 return epochToTime(mtime);
343 }
344
350 public int getUid() {
351 return uid;
352 }
353
359 public int getGid() {
360 return gid;
361 }
362
368 public long getMetaAddr() {
369 return metaAddr;
370 }
371
378 public long getMetaSeq() {
379 return metaSeq;
380 }
381
387 public String getModesAsString() {
389 String result = "";
390
394
398
402
406
407 // first character = the Meta Type
408 result += metaType.toString();
409
410 // second and third characters = user permissions
411 if ((mode & irusr) == irusr) {
412 result += "r"; //NON-NLS
413 } else {
414 result += "-"; //NON-NLS
415 }
416 if ((mode & iwusr) == iwusr) {
417 result += "w"; //NON-NLS
418 } else {
419 result += "-"; //NON-NLS
420 }
421
422 // fourth character = set uid
423 if ((mode & isuid) == isuid) {
424 if ((mode & ixusr) == ixusr) {
425 result += "s"; //NON-NLS
426 } else {
427 result += "S"; //NON-NLS
428 }
429 } else {
430 if ((mode & ixusr) == ixusr) {
431 result += "x"; //NON-NLS
432 } else {
433 result += "-"; //NON-NLS
434 }
435 }
436
437 // fifth and sixth characters = group permissions
438 if ((mode & irgrp) == irgrp) {
439 result += "r"; //NON-NLS
440 } else {
441 result += "-"; //NON-NLS
442 }
443 if ((mode & iwgrp) == iwgrp) {
444 result += "w"; //NON-NLS
445 } else {
446 result += "-"; //NON-NLS
447 }
448
449 // seventh character = set gid
450 if ((mode & isgid) == isgid) {
451 if ((mode & ixgrp) == ixgrp) {
452 result += "s"; //NON-NLS
453 } else {
454 result += "S"; //NON-NLS
455 }
456 } else {
457 if ((mode & ixgrp) == ixgrp) {
458 result += "x"; //NON-NLS
459 } else {
460 result += "-"; //NON-NLS
461 }
462 }
463
464 // eighth and ninth character = other permissions
465 if ((mode & iroth) == iroth) {
466 result += "r"; //NON-NLS
467 } else {
468 result += "-"; //NON-NLS
469 }
470 if ((mode & iwoth) == iwoth) {
471 result += "w"; //NON-NLS
472 } else {
473 result += "-"; //NON-NLS
474 }
475
476 // tenth character = sticky bit
477 if ((mode & isvtx) == isvtx) {
478 if ((mode & ixoth) == ixoth) {
479 result += "t"; //NON-NLS
480 } else {
481 result += "T"; //NON-NLS
482 }
483 } else {
484 if ((mode & ixoth) == ixoth) {
485 result += "x"; //NON-NLS
486 } else {
487 result += "-"; //NON-NLS
488 }
489 }
490
491 // check the result
492 if (result.length() != 10) {
493 // throw error here
494 result = "ERROR"; //NON-NLS
495 }
496 return result;
497 }
498
504 public String getMIMEType() {
505 return mimeType;
506 }
507
516 public void setMIMEType(String mimeType) {
517 this.mimeType = mimeType;
518 this.mimeTypeDirty = true;
519 }
520
522 return modes.contains(mode);
523 }
524
533 public void setMd5Hash(String md5Hash) {
534 this.md5Hash = md5Hash;
535 this.md5HashDirty = true;
536 }
537
543 public String getMd5Hash() {
544 return this.md5Hash;
545 }
546
555 public void setSha256Hash(String sha256Hash) {
556 this.sha256Hash = sha256Hash;
557 this.sha256HashDirty = true;
558 }
559
565 public String getSha256Hash() {
566 return this.sha256Hash;
567 }
568
577 public void setSha1Hash(String sha1Hash) {
578 this.sha1Hash = sha1Hash;
579 this.sha1HashDirty = true;
580 }
581
587 public String getSha1Hash() {
588 return this.sha1Hash;
589 }
590
598 public List<Attribute> getAttributes() throws TskCoreException {
599 synchronized (this) {
600 if (!loadedAttributesCacheFromDb) {
601 ArrayList<Attribute> attributes = getSleuthkitCase().getBlackboard().getFileAttributes(this);
602 fileAttributesCache.clear();
603 fileAttributesCache.addAll(attributes);
604 loadedAttributesCacheFromDb = true;
605 }
606 return Collections.unmodifiableList(fileAttributesCache);
607 }
608 }
609
623 public void addAttributes(Collection<Attribute> attributes, final SleuthkitCase.CaseDbTransaction caseDbTransaction) throws TskCoreException {
624
625 if (Objects.isNull(attributes) || attributes.isEmpty()) {
626 throw new TskCoreException("Illegal Argument passed to addAttributes: null or empty attributes passed to addAttributes");
627 }
628 boolean isLocalTransaction = Objects.isNull(caseDbTransaction);
629 SleuthkitCase.CaseDbTransaction localTransaction = isLocalTransaction ? getSleuthkitCase().beginTransaction() : null;
630 SleuthkitCase.CaseDbConnection connection = isLocalTransaction ? localTransaction.getConnection() : caseDbTransaction.getConnection();
631
632 try {
633 for (final Attribute attribute : attributes) {
634 attribute.setAttributeParentId(getId());
635 attribute.setCaseDatabase(getSleuthkitCase());
636 getSleuthkitCase().addFileAttribute(attribute, connection);
637 }
638
639 if (isLocalTransaction) {
640 localTransaction.commit();
641 localTransaction = null;
642 }
643 // append the new attributes if cache is already loaded.
644 synchronized (this) {
645 if (loadedAttributesCacheFromDb) {
646 fileAttributesCache.addAll(attributes);
647 }
648 }
649 } catch (SQLException ex) {
650 if (isLocalTransaction && null != localTransaction) {
651 try {
652 localTransaction.rollback();
653 } catch (TskCoreException ex2) {
654 LOGGER.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
655 }
656 }
657 throw new TskCoreException("Error adding file attributes", ex);
658 }
659 }
660
672 // don't allow them to downgrade the known state
673 if (this.knownState.compareTo(knownState) > 0) {
674 // ideally we'd return some kind of error, but
675 // the API doesn't allow it
676 return;
677 }
678 this.knownState = knownState;
679 this.knownStateDirty = true;
680 }
681
689 return knownState;
690 }
691
699 public String getNameExtension() {
700 return extension;
701 }
702
708 @Override
709 public long getSize() {
710 return size;
711 }
712
718 public String getParentPath() {
719 return parentPath;
720 }
721
733 @Override
735 return getSleuthkitCase().getContentById(this.dataSourceObjectId);
736 }
737
743 public long getDataSourceObjectId() {
744 return dataSourceObjectId;
745 }
746
753 return collected;
754 }
755
761 public void setCollected(TskData.CollectedStatus collected) {
762 this.collected = collected;
763 collectedDirty = true;
764 }
765
776 public List<TskFileRange> getRanges() throws TskCoreException {
777 if (ranges == null) {
778 ranges = getSleuthkitCase().getFileRanges(this.getId());
779 }
780 return ranges;
781 }
782
796 public long convertToImgOffset(long fileOffset) throws TskCoreException {
797 long imgOffset = -1;
798 for (TskFileRange byteRange : getRanges()) {
799
800 // if fileOffset is within the current byteRange, calculate the image
801 // offset and break
802 long rangeLength = byteRange.getByteLen();
803 if (fileOffset < rangeLength) {
804 imgOffset = byteRange.getByteStart() + fileOffset;
805 break;
806 }
807
808 // otherwise, decrement fileOffset by the length of the current
809 // byte range and continue
810 fileOffset -= rangeLength;
811 }
812 return imgOffset;
813 }
814
829 public List<TskFileRange> convertToImgRanges(long fileOffset, long length) throws TskCoreException {
830 if (fileOffset < 0 || length < 0) {
831 throw new TskCoreException("fileOffset and length must be non-negative");
832 }
833
834 List<TskFileRange> thisRanges = getRanges();
835 List<TskFileRange> toRet = new ArrayList<>();
836
837 long requestedEnd = fileOffset + length;
838
839 // the number of bytes counted from the beginning of this file
840 long bytesCounted = 0;
841
842 for (int curRangeIdx = 0; curRangeIdx < thisRanges.size(); curRangeIdx++) {
843 // if we exceeded length of requested, then we are done
844 if (bytesCounted >= requestedEnd) {
845 break;
846 }
847
848 TskFileRange curRange = thisRanges.get(curRangeIdx);
849 long curRangeLen = curRange.getByteLen();
850 // the bytes counted when we reach the end of this range
851 long curRangeEnd = bytesCounted + curRangeLen;
852
853 // if fileOffset is less than current range's end and we have not
854 // gone past the end we requested, then grab at least part of this
855 // range.
856 if (fileOffset < curRangeEnd) {
857 // offset into range to be returned to user (0 if fileOffset <= bytesCounted)
858 long rangeOffset = Math.max(0, fileOffset - bytesCounted);
859
860 // calculate the new TskFileRange start by adding on the offset into the current range
861 long newRangeStart = curRange.getByteStart() + rangeOffset;
862
863 // how much this current range exceeds the length requested (or 0 if within the length requested)
864 long rangeOvershoot = Math.max(0, curRangeEnd - requestedEnd);
865
866 long newRangeLen = curRangeLen - rangeOffset - rangeOvershoot;
867 toRet.add(new TskFileRange(newRangeStart, newRangeLen, toRet.size()));
868 }
869
870 bytesCounted = curRangeEnd;
871 }
872
873 return toRet;
874 }
875
887
901
912
929 @Beta
930 public int countChildrenOfType(List<TSK_FS_NAME_TYPE_ENUM> types) throws TskCoreException {
931 return getSleuthkitCase().getAbstractFileChildrenCountByType(this, types);
932 }
933
939 public abstract boolean isRoot();
940
949 public static String createNonUniquePath(String uniquePath) {
950
951 // split the path into parts
952 String[] pathSegments = uniquePath.split("/");
953
954 // see if uniquePath had an image and/or volume name
955 int index = 0;
956 if (pathSegments[0].startsWith("img_")) { //NON-NLS
957 ++index;
958 }
959 if (pathSegments[1].startsWith("vol_")) { //NON-NLS
960 ++index;
961 }
962
963 // Assemble the non-unique path (skipping over the image and volume
964 // name, if they exist).
965 StringBuilder strbuf = new StringBuilder();
966 for (; index < pathSegments.length; ++index) {
967 if (!pathSegments[index].isEmpty()) {
968 strbuf.append("/").append(pathSegments[index]);
969 }
970 }
971
972 return strbuf.toString();
973 }
974
981 public List<AbstractFile> listFiles() throws TskCoreException {
982 // first, get all children
983 List<Content> children = getChildren();
984
985 // only keep those that are of type AbstractFile
986 List<AbstractFile> files = new ArrayList<AbstractFile>();
987 for (Content child : children) {
988 if (child instanceof AbstractFile) {
989 AbstractFile afChild = (AbstractFile) child;
990 files.add(afChild);
991 }
992 }
993 return files;
994 }
995
1002 return metaType;
1003 }
1004
1005 public String getMetaTypeAsString() {
1006 return metaType.toString();
1007 }
1008
1015 return dirType;
1016 }
1017
1018 public String getDirTypeAsString() {
1019 return dirType.toString();
1020 }
1021
1028 return dirFlag == flag;
1029 }
1030
1035 public String getDirFlagAsString() {
1036 return dirFlag.toString();
1037 }
1038
1044 void setDirFlag(TSK_FS_NAME_FLAG_ENUM flag) {
1045 dirFlag = flag;
1046 }
1047
1051 public String getMetaFlagsAsString() {
1052 String str = "";
1053 if (metaFlags.contains(TSK_FS_META_FLAG_ENUM.ALLOC)) {
1054 str = TSK_FS_META_FLAG_ENUM.ALLOC.toString();
1055 } else if (metaFlags.contains(TSK_FS_META_FLAG_ENUM.UNALLOC)) {
1056 str = TSK_FS_META_FLAG_ENUM.UNALLOC.toString();
1057 }
1058 return str;
1059 }
1060
1066 public boolean isMetaFlagSet(TSK_FS_META_FLAG_ENUM metaFlag) {
1067 return metaFlags.contains(metaFlag);
1068 }
1069
1075 void setMetaFlag(TSK_FS_META_FLAG_ENUM metaFlag) {
1076 metaFlags.add(metaFlag);
1077 }
1078
1084 void removeMetaFlag(TSK_FS_META_FLAG_ENUM metaFlag) {
1085 metaFlags.remove(metaFlag);
1086 }
1087
1093 short getMetaFlagsAsInt() {
1094 return TSK_FS_META_FLAG_ENUM.toInt(metaFlags);
1095 }
1096
1108 private ContentProviderStream getContentProviderStream() throws TskCoreException {
1109 synchronized (contentProviderStreamLock) {
1110 // try to get soft reference content provider stream
1111 ContentProviderStream contentProviderStream = contentProviderStreamRef == null ? null : contentProviderStreamRef.get();
1112 // load if not cached and then cache if present
1113 if (contentProviderStream == null) {
1114 ContentStreamProvider provider = getSleuthkitCase().getContentProvider();
1115 contentProviderStream = provider == null ? null : provider.getContentStream(this).orElse(null);
1116
1117 if (contentProviderStream == null) {
1118 throw new TskCoreException(MessageFormat.format("Could not get content provider string for file with obj id: {0}, path: {1}",
1119 getId(),
1120 getUniquePath()));
1121 }
1122
1123 this.contentProviderStreamRef = new SoftReference<>(contentProviderStream);
1124 }
1125
1126 return contentProviderStream;
1127 }
1128 }
1129
1130 @Override
1131 public final int read(byte[] buf, long offset, long len) throws TskCoreException {
1132 // try to use content provider stream if should use
1133 if (tryContentProviderStream) {
1134 ContentProviderStream contentProviderStream = getContentProviderStream();
1135 return contentProviderStream.read(buf, offset, len);
1136 } else if (localPathSet) {
1137 //if localPath is set, use local, otherwise, use readCustom() supplied by derived class
1138 return readLocal(buf, offset, len);
1139 } else {
1140 return readInt(buf, offset, len);
1141 }
1142
1143 }
1144
1156 protected int readInt(byte[] buf, long offset, long len) throws TskCoreException {
1157 return 0;
1158 }
1159
1171 protected final int readLocal(byte[] buf, long offset, long len) throws TskCoreException {
1172 if (!localPathSet) {
1173 throw new TskCoreException(
1174 BUNDLE.getString("AbstractFile.readLocal.exception.msg1.text"));
1175 }
1176
1177 if (isDir()) {
1178 return 0;
1179 }
1180
1181 // If the file is empty, just return that zero bytes were read.
1182 if (getSize() == 0) {
1183 return 0;
1184 }
1185
1186 loadLocalFile();
1187
1188 int bytesRead = 0;
1189
1190 if (localFileHandle == null) {
1191 synchronized (this) {
1192 if (localFileHandle == null) {
1193 try {
1194 localFileHandle = new RandomAccessFile(localFile, "r");
1195 } catch (FileNotFoundException ex) {
1196 final String msg = MessageFormat.format(BUNDLE.getString(
1197 "AbstractFile.readLocal.exception.msg4.text"),
1198 localAbsPath);
1199 LOGGER.log(Level.SEVERE, msg, ex);
1200 //file could have been deleted or moved
1201 throw new TskCoreException(msg, ex);
1202 }
1203 }
1204 }
1205 }
1206
1207 try {
1208 if (!encodingType.equals(TskData.EncodingType.NONE)) {
1209 // The file is encoded, so we need to alter the offset to read (since there's
1210 // a header on the encoded file) and then decode each byte
1211 long encodedOffset = offset + EncodedFileUtil.getHeaderLength();
1212
1213 //move to the user request offset in the stream
1214 long curOffset = localFileHandle.getFilePointer();
1215 if (curOffset != encodedOffset) {
1216 localFileHandle.seek(encodedOffset);
1217 }
1218 bytesRead = localFileHandle.read(buf, 0, (int) len);
1219 for (int i = 0; i < bytesRead; i++) {
1220 buf[i] = EncodedFileUtil.decodeByte(buf[i], encodingType);
1221 }
1222 return bytesRead;
1223 } else {
1224 //move to the user request offset in the stream
1225 long curOffset = localFileHandle.getFilePointer();
1226 if (curOffset != offset) {
1227 localFileHandle.seek(offset);
1228 }
1229 //note, we are always writing at 0 offset of user buffer
1230 return localFileHandle.read(buf, 0, (int) len);
1231 }
1232 } catch (IOException ex) {
1233 final String msg = MessageFormat.format(BUNDLE.getString("AbstractFile.readLocal.exception.msg5.text"), localAbsPath);
1234 LOGGER.log(Level.SEVERE, msg, ex);
1235 //local file could have been deleted / moved
1236 throw new TskCoreException(msg, ex);
1237 }
1238 }
1239
1247 void setLocalFilePath(String localPath) {
1248
1249 if (localPath == null || localPath.equals("")) {
1250 this.localPath = "";
1251 localAbsPath = null;
1252 localPathSet = false;
1253 } else {
1254 // It should always be the case that absolute paths start with slashes or a windows drive letter
1255 // and relative paths do not, but some older versions of modules created derived file paths
1256 // starting with slashes. So we first check if this file is a DerivedFile before looking at the path.
1257 this.localPath = localPath;
1258 if (this instanceof DerivedFile) {
1259 // DerivedFiles always have relative paths
1260 this.localAbsPath = getSleuthkitCase().getDbDirPath() + java.io.File.separator + localPath;
1261 } else {
1262 // If a path starts with a slash or with a Windows drive letter, then it is
1263 // absolute. Otherwise it is relative.
1264 if (localPath.startsWith("/") || localPath.startsWith("\\")
1265 || localPath.matches("[A-Za-z]:[/\\\\].*")) {
1266 this.localAbsPath = localPath;
1267 } else {
1268 this.localAbsPath = getSleuthkitCase().getDbDirPath() + java.io.File.separator + localPath;
1269 }
1270 }
1271 this.localPathSet = true;
1272 }
1273 }
1274
1280 public String getLocalPath() {
1281 return localPath;
1282 }
1283
1289 public String getLocalAbsPath() {
1290 return localAbsPath;
1291 }
1292
1298 final void setEncodingType(TskData.EncodingType encodingType) {
1299 this.encodingType = encodingType;
1300 }
1301
1309 public boolean exists() {
1310 if (tryContentProviderStream || !localPathSet) {
1311 return true;
1312 } else {
1313 try {
1314 loadLocalFile();
1315 return localFile.exists();
1316 } catch (TskCoreException ex) {
1317 LOGGER.log(Level.SEVERE, ex.getMessage());
1318 return false;
1319 }
1320 }
1321 }
1322
1330 public boolean canRead() {
1331 if (tryContentProviderStream || !localPathSet) {
1332 return true;
1333 } else {
1334 try {
1335 loadLocalFile();
1336 return localFile.canRead();
1337 } catch (TskCoreException ex) {
1338 LOGGER.log(Level.SEVERE, ex.getMessage());
1339 return false;
1340 }
1341 }
1342 }
1343
1350 private void loadLocalFile() throws TskCoreException {
1351 if (!localPathSet) {
1352 throw new TskCoreException(
1353 BUNDLE.getString("AbstractFile.readLocal.exception.msg1.text"));
1354 }
1355
1356 // already been set
1357 if (localFile != null) {
1358 return;
1359 }
1360
1361 synchronized (this) {
1362 if (localFile == null) {
1363 localFile = new java.io.File(localAbsPath);
1364 }
1365 }
1366 }
1367
1368 @Override
1369 public void close() {
1370
1371 //close local file handle if set
1372 if (localFileHandle != null) {
1373 synchronized (this) {
1374 if (localFileHandle != null) {
1375 try {
1376 localFileHandle.close();
1377 } catch (IOException ex) {
1378 LOGGER.log(Level.SEVERE, "Could not close file handle for file: " + getParentPath() + getName(), ex); //NON-NLS
1379 }
1380 localFileHandle = null;
1381 }
1382 }
1383 }
1384
1385 }
1386
1387 @SuppressWarnings("deprecation")
1388 @Override
1389 protected void finalize() throws Throwable {
1390 try {
1391 close();
1392 } finally {
1393 super.finalize();
1394 }
1395 }
1396
1397 @Override
1398 public String toString(boolean preserveState) {
1399 return super.toString(preserveState) + "AbstractFile [\t" //NON-NLS
1400 + "\t" + "fileType " + fileType //NON-NLS
1401 + "\tctime " + ctime //NON-NLS
1402 + "\tcrtime " + crtime //NON-NLS
1403 + "\t" + "mtime " + mtime + "\t" + "atime " + atime //NON-NLS
1404 + "\t" + "attrId " + attrId //NON-NLS
1405 + "\t" + "attrType " + attrType //NON-NLS
1406 + "\t" + "dirFlag " + dirFlag + "\t" + "dirType " + dirType //NON-NLS
1407 + "\t" + "uid " + uid //NON-NLS
1408 + "\t" + "gid " + gid //NON-NLS
1409 + "\t" + "metaAddr " + metaAddr + "\t" + "metaSeq " + metaSeq + "\t" + "metaFlags " + metaFlags //NON-NLS
1410 + "\t" + "metaType " + metaType + "\t" + "modes " + modes //NON-NLS
1411 + "\t" + "parentPath " + parentPath + "\t" + "size " + size //NON-NLS
1412 + "\t" + "knownState " + knownState + "\t" + "md5Hash " + md5Hash + "\t" + "sha256Hash " + sha256Hash + "\t" + "sha1Hash " + sha1Hash//NON-NLS
1413 + "\t" + "localPathSet " + localPathSet + "\t" + "localPath " + localPath //NON-NLS
1414 + "\t" + "localAbsPath " + localAbsPath + "\t" + "localFile " + localFile //NON-NLS
1415 + "]\t";
1416 }
1417
1427
1436 public MimeMatchEnum isMimeType(SortedSet<String> mimeTypes) {
1437 if (this.mimeType == null) {
1438 return MimeMatchEnum.UNDEFINED;
1439 }
1440 if (mimeTypes.contains(this.mimeType)) {
1441 return MimeMatchEnum.TRUE;
1442 }
1443 return MimeMatchEnum.FALSE;
1444 }
1445
1453 public void save() throws TskCoreException {
1454 CaseDbTransaction transaction = null;
1455 try {
1456 transaction = getSleuthkitCase().beginTransaction();
1457 save(transaction);
1458 transaction.commit();
1459 } catch (TskCoreException ex) {
1460 if (transaction != null) {
1461 transaction.rollback();
1462 }
1463 throw ex;
1464 }
1465 }
1466
1477 public void save(CaseDbTransaction transaction) throws TskCoreException {
1478 if (!(md5HashDirty || sha256HashDirty || sha1HashDirty || mimeTypeDirty || knownStateDirty || collectedDirty)) {
1479 return;
1480 }
1481
1482 String updateSql = "";
1483 if (mimeTypeDirty) {
1484 updateSql = "mime_type = '" + this.getMIMEType() + "'";
1485 }
1486 if (md5HashDirty) {
1487 if (!updateSql.isEmpty()) {
1488 updateSql += ", ";
1489 }
1490 updateSql += "md5 = '" + this.getMd5Hash() + "'";
1491 }
1492 if (sha256HashDirty) {
1493 if (!updateSql.isEmpty()) {
1494 updateSql += ", ";
1495 }
1496 updateSql += "sha256 = '" + this.getSha256Hash() + "'";
1497 }
1498 if (sha1HashDirty) {
1499 if (!updateSql.isEmpty()) {
1500 updateSql += ", ";
1501 }
1502 updateSql += "sha1 = '" + this.getSha1Hash() + "'";
1503 }
1504 if (knownStateDirty) {
1505 if (!updateSql.isEmpty()) {
1506 updateSql += ", ";
1507 }
1508 updateSql += "known = '" + this.getKnown().getFileKnownValue() + "'";
1509 }
1510 if (collectedDirty) {
1511 if (!updateSql.isEmpty()) {
1512 updateSql += ", ";
1513 }
1514 updateSql += "collected = '" + this.getCollected().getType() + "'";
1515 }
1516 updateSql = "UPDATE tsk_files SET " + updateSql + " WHERE obj_id = " + this.getId();
1517
1518 SleuthkitCase.CaseDbConnection connection = transaction.getConnection();
1519 try (Statement statement = connection.createStatement()) {
1520 connection.executeUpdate(statement, updateSql);
1521 md5HashDirty = false;
1522 sha256HashDirty = false;
1523 sha1HashDirty = false;
1524 mimeTypeDirty = false;
1525 knownStateDirty = false;
1526 collectedDirty = false;
1527 } catch (SQLException ex) {
1528 throw new TskCoreException(String.format("Error updating properties of file %s (obj_id = %s)", getName(), getId()), ex);
1529 }
1530 }
1531
1540 public Optional<String> getOwnerUid() {
1541 return Optional.ofNullable(ownerUid);
1542 }
1543
1549 public Optional<Long> getOsAccountObjectId() {
1550 return Optional.ofNullable(osAccountObjId);
1551 }
1552
1558 void setFileSystem(FileSystem parent) {
1559 parentFileSystem = parent;
1560 }
1561
1567 public Optional<Long> getFileSystemObjectId() {
1568 return Optional.ofNullable(fileSystemObjectId);
1569 }
1570
1576 public boolean hasFileSystem() {
1577 return fileSystemObjectId != null;
1578 }
1579
1592 if (fileSystemObjectId == null) {
1593 throw new TskCoreException("File with ID: " + this.getId() + " does not belong to a file system");
1594 }
1595 if (parentFileSystem == null) {
1596 synchronized (this) {
1597 if (parentFileSystem == null) {
1598 parentFileSystem = getSleuthkitCase().getFileSystemById(fileSystemObjectId, AbstractContent.UNKNOWN_ID);
1599 }
1600 }
1601 }
1602 return parentFileSystem;
1603 }
1604
1613 @Override
1614 public String getUniquePath() throws TskCoreException {
1615
1616 if (uniquePath == null) {
1617 if (getFileSystemObjectId().isPresent()) {
1618 // For file system files, construct the path using the path to
1619 // the file system, the parent path, and the file name. FileSystem
1620 // objects are cached so this is unlikely to perform any
1621 // database operations.
1622 StringBuilder sb = new StringBuilder();
1623 sb.append(getFileSystem().getUniquePath());
1624 if (! parentPath.isEmpty()) {
1625 sb.append(parentPath);
1626 } else {
1627 // The parent path may not be set in older cases.
1628 sb.append("/");
1629 }
1630 sb.append(getName());
1631 uniquePath = sb.toString();
1632 } else {
1633 if ((this instanceof LayoutFile) && (parentPath.equals("/"))) {
1634 // This may be the case where the layout file is a direct child of a
1635 // volume. We want to make sure to include the volume information if present,
1636 // so go up the directory structure instead of using the optimized code.
1637 uniquePath = super.getUniquePath();
1639 parentPath.startsWith("/" + VirtualDirectory.NAME_CARVED) || parentPath.startsWith("/" + VirtualDirectory.NAME_UNALLOC)) {
1640 // We can make $Unalloc and $CarvedFiles under volumes without being part of a file system.
1641 // As above, we want to make sure to include the volume information if present,
1642 // so go up the directory structure instead of using the optimized code.
1643 uniquePath = super.getUniquePath();
1644 } else {
1645 // Optimized code to use for most files. Construct the path
1646 // using the data source name, the parent path, and the file name.
1647 // DataSource objects are cached so this is unlikely to perform any
1648 // database operations.
1649 String dataSourceName = "";
1650 Content dataSource = getDataSource();
1651 if (dataSource != null) {
1652 dataSourceName = dataSource.getUniquePath();
1653 }
1654 if (! parentPath.isEmpty()) {
1655 uniquePath = dataSourceName + parentPath + getName();
1656 } else {
1657 // The parent path may not be set in older cases.
1658 uniquePath = dataSourceName + "/" + getName();
1659 }
1660 }
1661 }
1662 }
1663 return uniquePath;
1664 }
1665
1666 @Deprecated
1667 @SuppressWarnings("deprecation")
1668 @Override
1669 public BlackboardArtifact newArtifact(int artifactTypeID) throws TskCoreException {
1670 return super.newArtifact(artifactTypeID);
1671 }
1672
1686 @Override
1687 public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection<BlackboardAttribute> attributesList) throws TskCoreException {
1688 return super.newDataArtifact(artifactType, attributesList, getOsAccountObjectId().orElse(null));
1689 }
1690
1699 @Deprecated
1700 @SuppressWarnings("deprecation")
1701 public short getAttrId() {
1702 /*
1703 * NOTE: previously attrId used to be stored in AbstractFile as (signed)
1704 * short even though it is stored as uint16 in TSK. In extremely rare
1705 * occurrences attrId can be larger than what a signed short can hold
1706 * (2^15). Changes were made to AbstractFile to store attrId as integer.
1707 * Therefore this method has been deprecated. For backwards
1708 * compatibility, attribute ids that are larger than 32K are converted
1709 * to a negative number.
1710 */
1711 return (short) attrId; // casting to signed short converts values over 32K to negative values
1712 }
1713
1725 @Deprecated
1726 protected void setLocalPath(String localPath, boolean isAbsolute) {
1727 setLocalFilePath(localPath);
1728 }
1729
1730 /*
1731 * -------------------------------------------------------------------------
1732 * Util methods to convert / map the data
1733 * -------------------------------------------------------------------------
1734 */
1744 @Deprecated
1745 public static String epochToTime(long epoch) {
1746 return TimeUtilities.epochToTime(epoch);
1747 }
1748
1760 @Deprecated
1761 public static String epochToTime(long epoch, TimeZone tzone) {
1762 return TimeUtilities.epochToTime(epoch, tzone);
1763 }
1764
1772 @Deprecated
1773 public static long timeToEpoch(String time) {
1774 return TimeUtilities.timeToEpoch(time);
1775 }
1776
1818 @Deprecated
1820 long objId,
1821 long dataSourceObjectId,
1822 Long fileSystemObjectId,
1824 String name,
1826 long metaAddr, int metaSeq,
1829 long size,
1830 long ctime, long crtime, long atime, long mtime,
1831 short modes,
1832 int uid, int gid,
1833 String md5Hash, String sha256Hash, String sha1Hash,
1835 String parentPath,
1836 String mimeType,
1837 String extension,
1838 String ownerUid,
1839 Long osAccountObjectId,
1840 List<Attribute> fileAttributes) {
1841 this(db, objId, dataSourceObjectId, fileSystemObjectId, attrType, attrId, name, fileType, metaAddr, metaSeq,
1843 md5Hash, sha256Hash, sha1Hash, knownState, parentPath, mimeType, extension,
1844 ownerUid, osAccountObjectId, TskData.CollectedStatus.UNKNOWN, fileAttributes);
1845 }
1846}
AbstractContent(SleuthkitCase db, long obj_id, String name)
TskData.CollectedStatus getCollected()
BlackboardArtifact newArtifact(int artifactTypeID)
final int readLocal(byte[] buf, long offset, long len)
TskData.TSK_FS_ATTR_TYPE_ENUM getAttrType()
int countChildrenOfType(List< TSK_FS_NAME_TYPE_ENUM > types)
Set< TSK_FS_META_FLAG_ENUM > metaFlags
final TSK_FS_NAME_TYPE_ENUM dirType
static String epochToTime(long epoch)
final TSK_FS_META_TYPE_ENUM metaType
void setKnown(TskData.FileKnown knownState)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection< BlackboardAttribute > attributesList)
void setSha256Hash(String sha256Hash)
MimeMatchEnum isMimeType(SortedSet< String > mimeTypes)
TskData.TSK_DB_FILES_TYPE_ENUM getType()
boolean isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM flag)
void save(CaseDbTransaction transaction)
final TskData.TSK_FS_ATTR_TYPE_ENUM attrType
boolean isModeSet(TskData.TSK_FS_META_MODE_ENUM mode)
final TskData.TSK_DB_FILES_TYPE_ENUM fileType
void setLocalPath(String localPath, boolean isAbsolute)
boolean isMetaFlagSet(TSK_FS_META_FLAG_ENUM metaFlag)
long convertToImgOffset(long fileOffset)
static long timeToEpoch(String time)
String toString(boolean preserveState)
void addAttributes(Collection< Attribute > attributes, final SleuthkitCase.CaseDbTransaction caseDbTransaction)
void setCollected(TskData.CollectedStatus collected)
static String epochToTime(long epoch, TimeZone tzone)
final Set< TskData.TSK_FS_META_MODE_ENUM > modes
List< TskFileRange > convertToImgRanges(long fileOffset, long length)
static String createNonUniquePath(String uniquePath)
int readInt(byte[] buf, long offset, long len)
final int read(byte[] buf, long offset, long len)
List< TskFileRange > getFileRanges(long id)
static String epochToTime(long epoch)
static long timeToEpoch(String time)
TRUE
file does not have a defined mime time in blackboard
FALSE
file has a defined mime type and it is one of the given ones
VIRTUAL_DIR
Virtual directory (not on fs) with no meta-data entry that can be used to group files of types other ...
Definition TskData.java:701
UNALLOC
Metadata structure is currently in an unallocated state.
Definition TskData.java:209
ALLOC
Metadata structure is currently in an allocated state.
Definition TskData.java:208
static short toInt(Set< TSK_FS_META_MODE_ENUM > modes)
Definition TskData.java:428
TSK_FS_META_TYPE_VIRT
"Virtual File" created by TSK for file system areas NON-NLS
Definition TskData.java:113
TSK_FS_META_TYPE_VIRT_DIR
"Virtual Directory" created by TSK for Orphan Files NON-NLS
Definition TskData.java:114
VIRT
Special (TSK added "Virtual" files) NON-NLS.
Definition TskData.java:50
int read(byte[] buf, long offset, long len)
Optional< ContentProviderStream > getContentStream(Content content)

Copyright © 2011-2024 Brian Carrier. (carrier -at- sleuthkit -dot- org)
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.