Sleuth Kit Java Bindings (JNI)  4.12.1
Java bindings for using The Sleuth Kit
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  */
19 package org.sleuthkit.datamodel;
20 
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.RandomAccessFile;
24 import java.lang.ref.SoftReference;
25 import java.sql.SQLException;
26 import java.sql.Statement;
27 import java.text.MessageFormat;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.List;
32 import java.util.Objects;
33 import java.util.Optional;
34 import java.util.ResourceBundle;
35 import java.util.Set;
36 import java.util.SortedSet;
37 import java.util.TimeZone;
38 import java.util.logging.Level;
39 import java.util.logging.Logger;
47 
52 public abstract class AbstractFile extends AbstractContent {
53 
55  protected final TSK_FS_NAME_TYPE_ENUM dirType;
58  protected Set<TSK_FS_META_FLAG_ENUM> metaFlags;
59  protected final Long fileSystemObjectId; // File system object ID; may be null
60  protected long size;
61  protected final long metaAddr, ctime, crtime, atime, mtime;
62  protected final int metaSeq;
63  protected final int uid, gid;
64  protected final int attrId;
66  protected final Set<TskData.TSK_FS_META_MODE_ENUM> modes;
67  //local file support
68  private boolean localPathSet = false;
69  private String localPath;
70  private String localAbsPath;
71  private volatile RandomAccessFile localFileHandle;
72  private volatile java.io.File localFile;
73  private TskData.EncodingType encodingType;
74  //range support
75  private List<TskFileRange> ranges;
76  /*
77  * path of parent directory
78  */
79  protected final String parentPath;
84  private boolean knownStateDirty = false;
85  /*
86  * md5 hash
87  */
88  protected String md5Hash;
89  private boolean md5HashDirty = false;
90  /*
91  * SHA-256 hash
92  */
93  protected String sha256Hash;
94  private boolean sha256HashDirty = false;
95 
96  /*
97  * SHA-1 hash
98  */
99  protected String sha1Hash;
100  private boolean sha1HashDirty = false;
101 
102  private TskData.CollectedStatus collected; // Collected status of file data
103  private boolean collectedDirty = false;
104 
105  private String mimeType;
106  private boolean mimeTypeDirty = false;
107  private static final Logger LOGGER = Logger.getLogger(AbstractFile.class.getName());
108  private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle");
109  private long dataSourceObjectId;
110  private final String extension;
111  private final List<Attribute> fileAttributesCache = new ArrayList<Attribute>();
112  private boolean loadedAttributesCacheFromDb = false;
113 
114  private final String ownerUid; // string owner uid, for example a Windows SID.
115  // different from the numeric uid which is more commonly found
116  // on Unix based file systems.
117  private final Long osAccountObjId; // obj id of the owner's OS account, may be null
118 
119  private volatile String uniquePath;
120  private volatile FileSystem parentFileSystem;
121 
122  private final boolean tryContentProviderStream;
123  private Object contentProviderStreamLock = new Object();
124  private SoftReference<ContentProviderStream> contentProviderStreamRef = null;
125 
168  long objId,
169  long dataSourceObjectId,
170  Long fileSystemObjectId,
172  String name,
174  long metaAddr, int metaSeq,
176  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags,
177  long size,
178  long ctime, long crtime, long atime, long mtime,
179  short modes,
180  int uid, int gid,
181  String md5Hash, String sha256Hash, String sha1Hash,
183  String parentPath,
184  String mimeType,
185  String extension,
186  String ownerUid,
187  Long osAccountObjectId,
188  TskData.CollectedStatus collected,
189  List<Attribute> fileAttributes) {
190  super(db, objId, name);
191  this.dataSourceObjectId = dataSourceObjectId;
192  if (fileSystemObjectId != null) {
193  // When reading from the result set, nulls are converted to zeros.
194  // Switch it to null.
195  if (fileSystemObjectId > 0) {
196  this.fileSystemObjectId = fileSystemObjectId;
197  } else {
198  this.fileSystemObjectId = null;
199  }
200  } else {
201  this.fileSystemObjectId = null;
202  }
203  this.attrType = attrType;
204  this.attrId = attrId;
205  this.fileType = fileType;
206  this.metaAddr = metaAddr;
207  this.metaSeq = metaSeq;
208  this.dirType = dirType;
209  this.metaType = metaType;
210  this.dirFlag = dirFlag;
211  this.metaFlags = TSK_FS_META_FLAG_ENUM.valuesOf(metaFlags);
212  this.size = size;
213  this.ctime = ctime;
214  this.crtime = crtime;
215  this.atime = atime;
216  this.mtime = mtime;
217  this.uid = uid;
218  this.gid = gid;
219  this.modes = TskData.TSK_FS_META_MODE_ENUM.valuesOf(modes);
220 
221  this.md5Hash = md5Hash;
222  this.sha256Hash = sha256Hash;
223  this.sha1Hash = sha1Hash;
224  if (knownState == null) {
225  this.knownState = FileKnown.UNKNOWN;
226  } else {
227  this.knownState = knownState;
228  }
229  this.parentPath = parentPath;
230  this.mimeType = mimeType;
231  this.extension = extension == null ? "" : extension;
232  this.encodingType = TskData.EncodingType.NONE;
233  this.ownerUid = ownerUid;
234  this.osAccountObjId = osAccountObjectId;
235  this.collected = collected;
236  // 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
237  // this will be flipped to false if there is no content provider stream from the content provider for this file
238  this.tryContentProviderStream = collected == CollectedStatus.YES_REPO && db.getContentProvider() != null;
239  if (Objects.nonNull(fileAttributes) && !fileAttributes.isEmpty()) {
240  this.fileAttributesCache.addAll(fileAttributes);
241  loadedAttributesCacheFromDb = true;
242  }
243  }
244 
251  return fileType;
252  }
253 
260  return attrType;
261  }
262 
268  public int getAttributeId() {
269  return attrId;
270  }
271 
277  public long getCtime() {
278  return ctime;
279  }
280 
286  public String getCtimeAsDate() {
287  return epochToTime(ctime);
288  }
289 
295  public long getCrtime() {
296  return crtime;
297  }
298 
304  public String getCrtimeAsDate() {
305  return epochToTime(crtime);
306  }
307 
313  public long getAtime() {
314  return atime;
315  }
316 
322  public String getAtimeAsDate() {
323  return epochToTime(atime);
324  }
325 
331  public long getMtime() {
332  return mtime;
333  }
334 
340  public String getMtimeAsDate() {
341  return epochToTime(mtime);
342  }
343 
349  public int getUid() {
350  return uid;
351  }
352 
358  public int getGid() {
359  return gid;
360  }
361 
367  public long getMetaAddr() {
368  return metaAddr;
369  }
370 
377  public long getMetaSeq() {
378  return metaSeq;
379  }
380 
386  public String getModesAsString() {
387  int mode = TskData.TSK_FS_META_MODE_ENUM.toInt(modes);
388  String result = "";
389 
390  short isuid = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_ISUID.getMode();
391  short isgid = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_ISGID.getMode();
392  short isvtx = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_ISVTX.getMode();
393 
394  short irusr = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IRUSR.getMode();
395  short iwusr = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IWUSR.getMode();
396  short ixusr = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IXUSR.getMode();
397 
398  short irgrp = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IRGRP.getMode();
399  short iwgrp = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IWGRP.getMode();
400  short ixgrp = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IXGRP.getMode();
401 
402  short iroth = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IROTH.getMode();
403  short iwoth = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IWOTH.getMode();
404  short ixoth = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IXOTH.getMode();
405 
406  // first character = the Meta Type
407  result += metaType.toString();
408 
409  // second and third characters = user permissions
410  if ((mode & irusr) == irusr) {
411  result += "r"; //NON-NLS
412  } else {
413  result += "-"; //NON-NLS
414  }
415  if ((mode & iwusr) == iwusr) {
416  result += "w"; //NON-NLS
417  } else {
418  result += "-"; //NON-NLS
419  }
420 
421  // fourth character = set uid
422  if ((mode & isuid) == isuid) {
423  if ((mode & ixusr) == ixusr) {
424  result += "s"; //NON-NLS
425  } else {
426  result += "S"; //NON-NLS
427  }
428  } else {
429  if ((mode & ixusr) == ixusr) {
430  result += "x"; //NON-NLS
431  } else {
432  result += "-"; //NON-NLS
433  }
434  }
435 
436  // fifth and sixth characters = group permissions
437  if ((mode & irgrp) == irgrp) {
438  result += "r"; //NON-NLS
439  } else {
440  result += "-"; //NON-NLS
441  }
442  if ((mode & iwgrp) == iwgrp) {
443  result += "w"; //NON-NLS
444  } else {
445  result += "-"; //NON-NLS
446  }
447 
448  // seventh character = set gid
449  if ((mode & isgid) == isgid) {
450  if ((mode & ixgrp) == ixgrp) {
451  result += "s"; //NON-NLS
452  } else {
453  result += "S"; //NON-NLS
454  }
455  } else {
456  if ((mode & ixgrp) == ixgrp) {
457  result += "x"; //NON-NLS
458  } else {
459  result += "-"; //NON-NLS
460  }
461  }
462 
463  // eighth and ninth character = other permissions
464  if ((mode & iroth) == iroth) {
465  result += "r"; //NON-NLS
466  } else {
467  result += "-"; //NON-NLS
468  }
469  if ((mode & iwoth) == iwoth) {
470  result += "w"; //NON-NLS
471  } else {
472  result += "-"; //NON-NLS
473  }
474 
475  // tenth character = sticky bit
476  if ((mode & isvtx) == isvtx) {
477  if ((mode & ixoth) == ixoth) {
478  result += "t"; //NON-NLS
479  } else {
480  result += "T"; //NON-NLS
481  }
482  } else {
483  if ((mode & ixoth) == ixoth) {
484  result += "x"; //NON-NLS
485  } else {
486  result += "-"; //NON-NLS
487  }
488  }
489 
490  // check the result
491  if (result.length() != 10) {
492  // throw error here
493  result = "ERROR"; //NON-NLS
494  }
495  return result;
496  }
497 
503  public String getMIMEType() {
504  return mimeType;
505  }
506 
515  public void setMIMEType(String mimeType) {
516  this.mimeType = mimeType;
517  this.mimeTypeDirty = true;
518  }
519 
520  public boolean isModeSet(TskData.TSK_FS_META_MODE_ENUM mode) {
521  return modes.contains(mode);
522  }
523 
532  public void setMd5Hash(String md5Hash) {
533  this.md5Hash = md5Hash;
534  this.md5HashDirty = true;
535  }
536 
542  public String getMd5Hash() {
543  return this.md5Hash;
544  }
545 
554  public void setSha256Hash(String sha256Hash) {
555  this.sha256Hash = sha256Hash;
556  this.sha256HashDirty = true;
557  }
558 
564  public String getSha256Hash() {
565  return this.sha256Hash;
566  }
567 
576  public void setSha1Hash(String sha1Hash) {
577  this.sha1Hash = sha1Hash;
578  this.sha1HashDirty = true;
579  }
580 
586  public String getSha1Hash() {
587  return this.sha1Hash;
588  }
589 
597  public List<Attribute> getAttributes() throws TskCoreException {
598  synchronized (this) {
599  if (!loadedAttributesCacheFromDb) {
600  ArrayList<Attribute> attributes = getSleuthkitCase().getBlackboard().getFileAttributes(this);
601  fileAttributesCache.clear();
602  fileAttributesCache.addAll(attributes);
603  loadedAttributesCacheFromDb = true;
604  }
605  return Collections.unmodifiableList(fileAttributesCache);
606  }
607  }
608 
622  public void addAttributes(Collection<Attribute> attributes, final SleuthkitCase.CaseDbTransaction caseDbTransaction) throws TskCoreException {
623 
624  if (Objects.isNull(attributes) || attributes.isEmpty()) {
625  throw new TskCoreException("Illegal Argument passed to addAttributes: null or empty attributes passed to addAttributes");
626  }
627  boolean isLocalTransaction = Objects.isNull(caseDbTransaction);
628  SleuthkitCase.CaseDbTransaction localTransaction = isLocalTransaction ? getSleuthkitCase().beginTransaction() : null;
629  SleuthkitCase.CaseDbConnection connection = isLocalTransaction ? localTransaction.getConnection() : caseDbTransaction.getConnection();
630 
631  try {
632  for (final Attribute attribute : attributes) {
633  attribute.setAttributeParentId(getId());
634  attribute.setCaseDatabase(getSleuthkitCase());
635  getSleuthkitCase().addFileAttribute(attribute, connection);
636  }
637 
638  if (isLocalTransaction) {
639  localTransaction.commit();
640  localTransaction = null;
641  }
642  // append the new attributes if cache is already loaded.
643  synchronized (this) {
644  if (loadedAttributesCacheFromDb) {
645  fileAttributesCache.addAll(attributes);
646  }
647  }
648  } catch (SQLException ex) {
649  if (isLocalTransaction && null != localTransaction) {
650  try {
651  localTransaction.rollback();
652  } catch (TskCoreException ex2) {
653  LOGGER.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
654  }
655  }
656  throw new TskCoreException("Error adding file attributes", ex);
657  }
658  }
659 
670  public void setKnown(TskData.FileKnown knownState) {
671  // don't allow them to downgrade the known state
672  if (this.knownState.compareTo(knownState) > 0) {
673  // ideally we'd return some kind of error, but
674  // the API doesn't allow it
675  return;
676  }
677  this.knownState = knownState;
678  this.knownStateDirty = true;
679  }
680 
688  return knownState;
689  }
690 
698  public String getNameExtension() {
699  return extension;
700  }
701 
707  @Override
708  public long getSize() {
709  return size;
710  }
711 
717  public String getParentPath() {
718  return parentPath;
719  }
720 
732  @Override
734  return getSleuthkitCase().getContentById(this.dataSourceObjectId);
735  }
736 
742  public long getDataSourceObjectId() {
743  return dataSourceObjectId;
744  }
745 
752  return collected;
753  }
754 
760  public void setCollected(TskData.CollectedStatus collected) {
761  this.collected = collected;
762  collectedDirty = true;
763  }
764 
775  public List<TskFileRange> getRanges() throws TskCoreException {
776  if (ranges == null) {
777  ranges = getSleuthkitCase().getFileRanges(this.getId());
778  }
779  return ranges;
780  }
781 
795  public long convertToImgOffset(long fileOffset) throws TskCoreException {
796  long imgOffset = -1;
797  for (TskFileRange byteRange : getRanges()) {
798 
799  // if fileOffset is within the current byteRange, calculate the image
800  // offset and break
801  long rangeLength = byteRange.getByteLen();
802  if (fileOffset < rangeLength) {
803  imgOffset = byteRange.getByteStart() + fileOffset;
804  break;
805  }
806 
807  // otherwise, decrement fileOffset by the length of the current
808  // byte range and continue
809  fileOffset -= rangeLength;
810  }
811  return imgOffset;
812  }
813 
828  public List<TskFileRange> convertToImgRanges(long fileOffset, long length) throws TskCoreException {
829  if (fileOffset < 0 || length < 0) {
830  throw new TskCoreException("fileOffset and length must be non-negative");
831  }
832 
833  List<TskFileRange> thisRanges = getRanges();
834  List<TskFileRange> toRet = new ArrayList<>();
835 
836  long requestedEnd = fileOffset + length;
837 
838  // the number of bytes counted from the beginning of this file
839  long bytesCounted = 0;
840 
841  for (int curRangeIdx = 0; curRangeIdx < thisRanges.size(); curRangeIdx++) {
842  // if we exceeded length of requested, then we are done
843  if (bytesCounted >= requestedEnd) {
844  break;
845  }
846 
847  TskFileRange curRange = thisRanges.get(curRangeIdx);
848  long curRangeLen = curRange.getByteLen();
849  // the bytes counted when we reach the end of this range
850  long curRangeEnd = bytesCounted + curRangeLen;
851 
852  // if fileOffset is less than current range's end and we have not
853  // gone past the end we requested, then grab at least part of this
854  // range.
855  if (fileOffset < curRangeEnd) {
856  // offset into range to be returned to user (0 if fileOffset <= bytesCounted)
857  long rangeOffset = Math.max(0, fileOffset - bytesCounted);
858 
859  // calculate the new TskFileRange start by adding on the offset into the current range
860  long newRangeStart = curRange.getByteStart() + rangeOffset;
861 
862  // how much this current range exceeds the length requested (or 0 if within the length requested)
863  long rangeOvershoot = Math.max(0, curRangeEnd - requestedEnd);
864 
865  long newRangeLen = curRangeLen - rangeOffset - rangeOvershoot;
866  toRet.add(new TskFileRange(newRangeStart, newRangeLen, toRet.size()));
867  }
868 
869  bytesCounted = curRangeEnd;
870  }
871 
872  return toRet;
873  }
874 
881  public boolean isVirtual() {
883  || dirType.equals(TskData.TSK_FS_NAME_TYPE_ENUM.VIRT)
885  }
886 
894  public boolean isFile() {
895  return metaType.equals(TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG)
896  || (metaType.equals(TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_UNDEF)
897  && dirType.equals(TSK_FS_NAME_TYPE_ENUM.REG));
898 
899  }
900 
907  public boolean isDir() {
908  return (metaType.equals(TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR)
910  }
911 
917  public abstract boolean isRoot();
918 
927  public static String createNonUniquePath(String uniquePath) {
928 
929  // split the path into parts
930  String[] pathSegments = uniquePath.split("/");
931 
932  // see if uniquePath had an image and/or volume name
933  int index = 0;
934  if (pathSegments[0].startsWith("img_")) { //NON-NLS
935  ++index;
936  }
937  if (pathSegments[1].startsWith("vol_")) { //NON-NLS
938  ++index;
939  }
940 
941  // Assemble the non-unique path (skipping over the image and volume
942  // name, if they exist).
943  StringBuilder strbuf = new StringBuilder();
944  for (; index < pathSegments.length; ++index) {
945  if (!pathSegments[index].isEmpty()) {
946  strbuf.append("/").append(pathSegments[index]);
947  }
948  }
949 
950  return strbuf.toString();
951  }
952 
959  public List<AbstractFile> listFiles() throws TskCoreException {
960  // first, get all children
961  List<Content> children = getChildren();
962 
963  // only keep those that are of type AbstractFile
964  List<AbstractFile> files = new ArrayList<AbstractFile>();
965  for (Content child : children) {
966  if (child instanceof AbstractFile) {
967  AbstractFile afChild = (AbstractFile) child;
968  files.add(afChild);
969  }
970  }
971  return files;
972  }
973 
980  return metaType;
981  }
982 
983  public String getMetaTypeAsString() {
984  return metaType.toString();
985  }
986 
993  return dirType;
994  }
995 
996  public String getDirTypeAsString() {
997  return dirType.toString();
998  }
999 
1006  return dirFlag == flag;
1007  }
1008 
1013  public String getDirFlagAsString() {
1014  return dirFlag.toString();
1015  }
1016 
1022  void setDirFlag(TSK_FS_NAME_FLAG_ENUM flag) {
1023  dirFlag = flag;
1024  }
1025 
1029  public String getMetaFlagsAsString() {
1030  String str = "";
1031  if (metaFlags.contains(TSK_FS_META_FLAG_ENUM.ALLOC)) {
1032  str = TSK_FS_META_FLAG_ENUM.ALLOC.toString();
1033  } else if (metaFlags.contains(TSK_FS_META_FLAG_ENUM.UNALLOC)) {
1034  str = TSK_FS_META_FLAG_ENUM.UNALLOC.toString();
1035  }
1036  return str;
1037  }
1038 
1044  public boolean isMetaFlagSet(TSK_FS_META_FLAG_ENUM metaFlag) {
1045  return metaFlags.contains(metaFlag);
1046  }
1047 
1053  void setMetaFlag(TSK_FS_META_FLAG_ENUM metaFlag) {
1054  metaFlags.add(metaFlag);
1055  }
1056 
1062  void removeMetaFlag(TSK_FS_META_FLAG_ENUM metaFlag) {
1063  metaFlags.remove(metaFlag);
1064  }
1065 
1071  short getMetaFlagsAsInt() {
1072  return TSK_FS_META_FLAG_ENUM.toInt(metaFlags);
1073  }
1074 
1086  private ContentProviderStream getContentProviderStream() throws TskCoreException {
1087  synchronized (contentProviderStreamLock) {
1088  // try to get soft reference content provider stream
1089  ContentProviderStream contentProviderStream = contentProviderStreamRef == null ? null : contentProviderStreamRef.get();
1090  // load if not cached and then cache if present
1091  if (contentProviderStream == null) {
1092  ContentStreamProvider provider = getSleuthkitCase().getContentProvider();
1093  contentProviderStream = provider == null ? null : provider.getContentStream(this).orElse(null);
1094 
1095  if (contentProviderStream == null) {
1096  throw new TskCoreException(MessageFormat.format("Could not get content provider string for file with obj id: {0}, path: {1}",
1097  getId(),
1098  getUniquePath()));
1099  }
1100 
1101  this.contentProviderStreamRef = new SoftReference<>(contentProviderStream);
1102  }
1103 
1104  return contentProviderStream;
1105  }
1106  }
1107 
1108  @Override
1109  public final int read(byte[] buf, long offset, long len) throws TskCoreException {
1110  // try to use content provider stream if should use
1111  if (tryContentProviderStream) {
1112  ContentProviderStream contentProviderStream = getContentProviderStream();
1113  return contentProviderStream.read(buf, offset, len);
1114  } else if (localPathSet) {
1115  //if localPath is set, use local, otherwise, use readCustom() supplied by derived class
1116  return readLocal(buf, offset, len);
1117  } else {
1118  return readInt(buf, offset, len);
1119  }
1120 
1121  }
1122 
1134  protected int readInt(byte[] buf, long offset, long len) throws TskCoreException {
1135  return 0;
1136  }
1137 
1149  protected final int readLocal(byte[] buf, long offset, long len) throws TskCoreException {
1150  if (!localPathSet) {
1151  throw new TskCoreException(
1152  BUNDLE.getString("AbstractFile.readLocal.exception.msg1.text"));
1153  }
1154 
1155  if (isDir()) {
1156  return 0;
1157  }
1158 
1159  // If the file is empty, just return that zero bytes were read.
1160  if (getSize() == 0) {
1161  return 0;
1162  }
1163 
1164  loadLocalFile();
1165 
1166  int bytesRead = 0;
1167 
1168  if (localFileHandle == null) {
1169  synchronized (this) {
1170  if (localFileHandle == null) {
1171  try {
1172  localFileHandle = new RandomAccessFile(localFile, "r");
1173  } catch (FileNotFoundException ex) {
1174  final String msg = MessageFormat.format(BUNDLE.getString(
1175  "AbstractFile.readLocal.exception.msg4.text"),
1176  localAbsPath);
1177  LOGGER.log(Level.SEVERE, msg, ex);
1178  //file could have been deleted or moved
1179  throw new TskCoreException(msg, ex);
1180  }
1181  }
1182  }
1183  }
1184 
1185  try {
1186  if (!encodingType.equals(TskData.EncodingType.NONE)) {
1187  // The file is encoded, so we need to alter the offset to read (since there's
1188  // a header on the encoded file) and then decode each byte
1189  long encodedOffset = offset + EncodedFileUtil.getHeaderLength();
1190 
1191  //move to the user request offset in the stream
1192  long curOffset = localFileHandle.getFilePointer();
1193  if (curOffset != encodedOffset) {
1194  localFileHandle.seek(encodedOffset);
1195  }
1196  bytesRead = localFileHandle.read(buf, 0, (int) len);
1197  for (int i = 0; i < bytesRead; i++) {
1198  buf[i] = EncodedFileUtil.decodeByte(buf[i], encodingType);
1199  }
1200  return bytesRead;
1201  } else {
1202  //move to the user request offset in the stream
1203  long curOffset = localFileHandle.getFilePointer();
1204  if (curOffset != offset) {
1205  localFileHandle.seek(offset);
1206  }
1207  //note, we are always writing at 0 offset of user buffer
1208  return localFileHandle.read(buf, 0, (int) len);
1209  }
1210  } catch (IOException ex) {
1211  final String msg = MessageFormat.format(BUNDLE.getString("AbstractFile.readLocal.exception.msg5.text"), localAbsPath);
1212  LOGGER.log(Level.SEVERE, msg, ex);
1213  //local file could have been deleted / moved
1214  throw new TskCoreException(msg, ex);
1215  }
1216  }
1217 
1225  void setLocalFilePath(String localPath) {
1226 
1227  if (localPath == null || localPath.equals("")) {
1228  this.localPath = "";
1229  localAbsPath = null;
1230  localPathSet = false;
1231  } else {
1232  // It should always be the case that absolute paths start with slashes or a windows drive letter
1233  // and relative paths do not, but some older versions of modules created derived file paths
1234  // starting with slashes. So we first check if this file is a DerivedFile before looking at the path.
1235  this.localPath = localPath;
1236  if (this instanceof DerivedFile) {
1237  // DerivedFiles always have relative paths
1238  this.localAbsPath = getSleuthkitCase().getDbDirPath() + java.io.File.separator + localPath;
1239  } else {
1240  // If a path starts with a slash or with a Windows drive letter, then it is
1241  // absolute. Otherwise it is relative.
1242  if (localPath.startsWith("/") || localPath.startsWith("\\")
1243  || localPath.matches("[A-Za-z]:[/\\\\].*")) {
1244  this.localAbsPath = localPath;
1245  } else {
1246  this.localAbsPath = getSleuthkitCase().getDbDirPath() + java.io.File.separator + localPath;
1247  }
1248  }
1249  this.localPathSet = true;
1250  }
1251  }
1252 
1258  public String getLocalPath() {
1259  return localPath;
1260  }
1261 
1267  public String getLocalAbsPath() {
1268  return localAbsPath;
1269  }
1270 
1276  final void setEncodingType(TskData.EncodingType encodingType) {
1277  this.encodingType = encodingType;
1278  }
1279 
1287  public boolean exists() {
1288  if (tryContentProviderStream || !localPathSet) {
1289  return true;
1290  } else {
1291  try {
1292  loadLocalFile();
1293  return localFile.exists();
1294  } catch (TskCoreException ex) {
1295  LOGGER.log(Level.SEVERE, ex.getMessage());
1296  return false;
1297  }
1298  }
1299  }
1300 
1308  public boolean canRead() {
1309  if (tryContentProviderStream || !localPathSet) {
1310  return true;
1311  } else {
1312  try {
1313  loadLocalFile();
1314  return localFile.canRead();
1315  } catch (TskCoreException ex) {
1316  LOGGER.log(Level.SEVERE, ex.getMessage());
1317  return false;
1318  }
1319  }
1320  }
1321 
1328  private void loadLocalFile() throws TskCoreException {
1329  if (!localPathSet) {
1330  throw new TskCoreException(
1331  BUNDLE.getString("AbstractFile.readLocal.exception.msg1.text"));
1332  }
1333 
1334  // already been set
1335  if (localFile != null) {
1336  return;
1337  }
1338 
1339  synchronized (this) {
1340  if (localFile == null) {
1341  localFile = new java.io.File(localAbsPath);
1342  }
1343  }
1344  }
1345 
1346  @Override
1347  public void close() {
1348 
1349  //close local file handle if set
1350  if (localFileHandle != null) {
1351  synchronized (this) {
1352  if (localFileHandle != null) {
1353  try {
1354  localFileHandle.close();
1355  } catch (IOException ex) {
1356  LOGGER.log(Level.SEVERE, "Could not close file handle for file: " + getParentPath() + getName(), ex); //NON-NLS
1357  }
1358  localFileHandle = null;
1359  }
1360  }
1361  }
1362 
1363  }
1364 
1365  @SuppressWarnings("deprecation")
1366  @Override
1367  protected void finalize() throws Throwable {
1368  try {
1369  close();
1370  } finally {
1371  super.finalize();
1372  }
1373  }
1374 
1375  @Override
1376  public String toString(boolean preserveState) {
1377  return super.toString(preserveState) + "AbstractFile [\t" //NON-NLS
1378  + "\t" + "fileType " + fileType //NON-NLS
1379  + "\tctime " + ctime //NON-NLS
1380  + "\tcrtime " + crtime //NON-NLS
1381  + "\t" + "mtime " + mtime + "\t" + "atime " + atime //NON-NLS
1382  + "\t" + "attrId " + attrId //NON-NLS
1383  + "\t" + "attrType " + attrType //NON-NLS
1384  + "\t" + "dirFlag " + dirFlag + "\t" + "dirType " + dirType //NON-NLS
1385  + "\t" + "uid " + uid //NON-NLS
1386  + "\t" + "gid " + gid //NON-NLS
1387  + "\t" + "metaAddr " + metaAddr + "\t" + "metaSeq " + metaSeq + "\t" + "metaFlags " + metaFlags //NON-NLS
1388  + "\t" + "metaType " + metaType + "\t" + "modes " + modes //NON-NLS
1389  + "\t" + "parentPath " + parentPath + "\t" + "size " + size //NON-NLS
1390  + "\t" + "knownState " + knownState + "\t" + "md5Hash " + md5Hash + "\t" + "sha256Hash " + sha256Hash + "\t" + "sha1Hash " + sha1Hash//NON-NLS
1391  + "\t" + "localPathSet " + localPathSet + "\t" + "localPath " + localPath //NON-NLS
1392  + "\t" + "localAbsPath " + localAbsPath + "\t" + "localFile " + localFile //NON-NLS
1393  + "]\t";
1394  }
1395 
1399  public enum MimeMatchEnum {
1400 
1403  FALSE
1404  }
1405 
1414  public MimeMatchEnum isMimeType(SortedSet<String> mimeTypes) {
1415  if (this.mimeType == null) {
1416  return MimeMatchEnum.UNDEFINED;
1417  }
1418  if (mimeTypes.contains(this.mimeType)) {
1419  return MimeMatchEnum.TRUE;
1420  }
1421  return MimeMatchEnum.FALSE;
1422  }
1423 
1431  public void save() throws TskCoreException {
1432  CaseDbTransaction transaction = null;
1433  try {
1434  transaction = getSleuthkitCase().beginTransaction();
1435  save(transaction);
1436  transaction.commit();
1437  } catch (TskCoreException ex) {
1438  if (transaction != null) {
1439  transaction.rollback();
1440  }
1441  throw ex;
1442  }
1443  }
1444 
1455  public void save(CaseDbTransaction transaction) throws TskCoreException {
1456  if (!(md5HashDirty || sha256HashDirty || sha1HashDirty || mimeTypeDirty || knownStateDirty || collectedDirty)) {
1457  return;
1458  }
1459 
1460  String updateSql = "";
1461  if (mimeTypeDirty) {
1462  updateSql = "mime_type = '" + this.getMIMEType() + "'";
1463  }
1464  if (md5HashDirty) {
1465  if (!updateSql.isEmpty()) {
1466  updateSql += ", ";
1467  }
1468  updateSql += "md5 = '" + this.getMd5Hash() + "'";
1469  }
1470  if (sha256HashDirty) {
1471  if (!updateSql.isEmpty()) {
1472  updateSql += ", ";
1473  }
1474  updateSql += "sha256 = '" + this.getSha256Hash() + "'";
1475  }
1476  if (sha1HashDirty) {
1477  if (!updateSql.isEmpty()) {
1478  updateSql += ", ";
1479  }
1480  updateSql += "sha1 = '" + this.getSha1Hash() + "'";
1481  }
1482  if (knownStateDirty) {
1483  if (!updateSql.isEmpty()) {
1484  updateSql += ", ";
1485  }
1486  updateSql += "known = '" + this.getKnown().getFileKnownValue() + "'";
1487  }
1488  if (collectedDirty) {
1489  if (!updateSql.isEmpty()) {
1490  updateSql += ", ";
1491  }
1492  updateSql += "collected = '" + this.getCollected().getType() + "'";
1493  }
1494  updateSql = "UPDATE tsk_files SET " + updateSql + " WHERE obj_id = " + this.getId();
1495 
1496  SleuthkitCase.CaseDbConnection connection = transaction.getConnection();
1497  try (Statement statement = connection.createStatement()) {
1498  connection.executeUpdate(statement, updateSql);
1499  md5HashDirty = false;
1500  sha256HashDirty = false;
1501  sha1HashDirty = false;
1502  mimeTypeDirty = false;
1503  knownStateDirty = false;
1504  collectedDirty = false;
1505  } catch (SQLException ex) {
1506  throw new TskCoreException(String.format("Error updating properties of file %s (obj_id = %s)", getName(), getId()), ex);
1507  }
1508  }
1509 
1518  public Optional<String> getOwnerUid() {
1519  return Optional.ofNullable(ownerUid);
1520  }
1521 
1527  public Optional<Long> getOsAccountObjectId() {
1528  return Optional.ofNullable(osAccountObjId);
1529  }
1530 
1536  void setFileSystem(FileSystem parent) {
1537  parentFileSystem = parent;
1538  }
1539 
1545  public Optional<Long> getFileSystemObjectId() {
1546  return Optional.ofNullable(fileSystemObjectId);
1547  }
1548 
1554  public boolean hasFileSystem() {
1555  return fileSystemObjectId != null;
1556  }
1557 
1569  public FileSystem getFileSystem() throws TskCoreException {
1570  if (fileSystemObjectId == null) {
1571  throw new TskCoreException("File with ID: " + this.getId() + " does not belong to a file system");
1572  }
1573  if (parentFileSystem == null) {
1574  synchronized (this) {
1575  if (parentFileSystem == null) {
1576  parentFileSystem = getSleuthkitCase().getFileSystemById(fileSystemObjectId, AbstractContent.UNKNOWN_ID);
1577  }
1578  }
1579  }
1580  return parentFileSystem;
1581  }
1582 
1591  @Override
1592  public String getUniquePath() throws TskCoreException {
1593 
1594  if (uniquePath == null) {
1595  if (getFileSystemObjectId().isPresent()) {
1596  // For file system files, construct the path using the path to
1597  // the file system, the parent path, and the file name. FileSystem
1598  // objects are cached so this is unlikely to perform any
1599  // database operations.
1600  StringBuilder sb = new StringBuilder();
1601  sb.append(getFileSystem().getUniquePath());
1602  if (! parentPath.isEmpty()) {
1603  sb.append(parentPath);
1604  } else {
1605  // The parent path may not be set in older cases.
1606  sb.append("/");
1607  }
1608  sb.append(getName());
1609  uniquePath = sb.toString();
1610  } else {
1611  if ((this instanceof LayoutFile) && (parentPath.equals("/"))) {
1612  // This may be the case where the layout file is a direct child of a
1613  // volume. We want to make sure to include the volume information if present,
1614  // so go up the directory structure instead of using the optimized code.
1615  uniquePath = super.getUniquePath();
1617  parentPath.startsWith("/" + VirtualDirectory.NAME_CARVED) || parentPath.startsWith("/" + VirtualDirectory.NAME_UNALLOC)) {
1618  // We can make $Unalloc and $CarvedFiles under volumes without being part of a file system.
1619  // As above, we want to make sure to include the volume information if present,
1620  // so go up the directory structure instead of using the optimized code.
1621  uniquePath = super.getUniquePath();
1622  } else {
1623  // Optimized code to use for most files. Construct the path
1624  // using the data source name, the parent path, and the file name.
1625  // DataSource objects are cached so this is unlikely to perform any
1626  // database operations.
1627  String dataSourceName = "";
1628  Content dataSource = getDataSource();
1629  if (dataSource != null) {
1630  dataSourceName = dataSource.getUniquePath();
1631  }
1632  if (! parentPath.isEmpty()) {
1633  uniquePath = dataSourceName + parentPath + getName();
1634  } else {
1635  // The parent path may not be set in older cases.
1636  uniquePath = dataSourceName + "/" + getName();
1637  }
1638  }
1639  }
1640  }
1641  return uniquePath;
1642  }
1643 
1644  @Deprecated
1645  @SuppressWarnings("deprecation")
1646  @Override
1647  public BlackboardArtifact newArtifact(int artifactTypeID) throws TskCoreException {
1648  return super.newArtifact(artifactTypeID);
1649  }
1650 
1664  @Override
1665  public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection<BlackboardAttribute> attributesList) throws TskCoreException {
1666  return super.newDataArtifact(artifactType, attributesList, getOsAccountObjectId().orElse(null));
1667  }
1668 
1677  @Deprecated
1678  @SuppressWarnings("deprecation")
1679  public short getAttrId() {
1680  /*
1681  * NOTE: previously attrId used to be stored in AbstractFile as (signed)
1682  * short even though it is stored as uint16 in TSK. In extremely rare
1683  * occurrences attrId can be larger than what a signed short can hold
1684  * (2^15). Changes were made to AbstractFile to store attrId as integer.
1685  * Therefore this method has been deprecated. For backwards
1686  * compatibility, attribute ids that are larger than 32K are converted
1687  * to a negative number.
1688  */
1689  return (short) attrId; // casting to signed short converts values over 32K to negative values
1690  }
1691 
1703  @Deprecated
1704  protected void setLocalPath(String localPath, boolean isAbsolute) {
1705  setLocalFilePath(localPath);
1706  }
1707 
1708  /*
1709  * -------------------------------------------------------------------------
1710  * Util methods to convert / map the data
1711  * -------------------------------------------------------------------------
1712  */
1722  @Deprecated
1723  public static String epochToTime(long epoch) {
1724  return TimeUtilities.epochToTime(epoch);
1725  }
1726 
1738  @Deprecated
1739  public static String epochToTime(long epoch, TimeZone tzone) {
1740  return TimeUtilities.epochToTime(epoch, tzone);
1741  }
1742 
1750  @Deprecated
1751  public static long timeToEpoch(String time) {
1752  return TimeUtilities.timeToEpoch(time);
1753  }
1754 
1796  @Deprecated
1798  long objId,
1799  long dataSourceObjectId,
1800  Long fileSystemObjectId,
1802  String name,
1804  long metaAddr, int metaSeq,
1805  TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType,
1806  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags,
1807  long size,
1808  long ctime, long crtime, long atime, long mtime,
1809  short modes,
1810  int uid, int gid,
1811  String md5Hash, String sha256Hash, String sha1Hash,
1812  FileKnown knownState,
1813  String parentPath,
1814  String mimeType,
1815  String extension,
1816  String ownerUid,
1817  Long osAccountObjectId,
1818  List<Attribute> fileAttributes) {
1819  this(db, objId, dataSourceObjectId, fileSystemObjectId, attrType, attrId, name, fileType, metaAddr, metaSeq,
1820  dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid,
1821  md5Hash, sha256Hash, sha1Hash, knownState, parentPath, mimeType, extension,
1822  ownerUid, osAccountObjectId, TskData.CollectedStatus.UNKNOWN, fileAttributes);
1823  }
1824 }
VIRT
Special (TSK added "Virtual" files) NON-NLS.
Definition: TskData.java:50
boolean isModeSet(TskData.TSK_FS_META_MODE_ENUM mode)
final TSK_FS_NAME_TYPE_ENUM dirType
static long timeToEpoch(String time)
static String epochToTime(long epoch)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection< BlackboardAttribute > attributesList, Long osAccountId)
static String epochToTime(long epoch)
final int readLocal(byte[] buf, long offset, long len)
boolean isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM flag)
ALLOC
Metadata structure is currently in an allocated state.
Definition: TskData.java:208
void setSha256Hash(String sha256Hash)
final TskData.TSK_DB_FILES_TYPE_ENUM fileType
UNALLOC
Metadata structure is currently in an unallocated state.
Definition: TskData.java:209
TskData.TSK_DB_FILES_TYPE_ENUM getType()
final TskData.TSK_FS_ATTR_TYPE_ENUM attrType
TSK_FS_META_TYPE_VIRT_DIR
"Virtual Directory" created by TSK for Orphan Files NON-NLS
Definition: TskData.java:114
long convertToImgOffset(long fileOffset)
TSK_FS_NAME_TYPE_ENUM getDirType()
BlackboardArtifact newArtifact(int artifactTypeID)
MimeMatchEnum isMimeType(SortedSet< String > mimeTypes)
void setCollected(TskData.CollectedStatus collected)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection< BlackboardAttribute > attributesList)
String toString(boolean preserveState)
Set< TSK_FS_META_FLAG_ENUM > metaFlags
void setKnown(TskData.FileKnown knownState)
BlackboardArtifact newArtifact(int artifactTypeID)
FALSE
file has a defined mime type and it is one of the given ones
final Set< TskData.TSK_FS_META_MODE_ENUM > modes
TSK_FS_META_TYPE_VIRT
"Virtual File" created by TSK for file system areas NON-NLS
Definition: TskData.java:113
TSK_FS_META_TYPE_ENUM getMetaType()
boolean isMetaFlagSet(TSK_FS_META_FLAG_ENUM metaFlag)
TRUE
file does not have a defined mime time in blackboard
static short toInt(Set< TSK_FS_META_MODE_ENUM > modes)
Definition: TskData.java:429
Optional< ContentProviderStream > getContentStream(Content content)
static String epochToTime(long epoch, TimeZone tzone)
static long timeToEpoch(String time)
int readInt(byte[] buf, long offset, long len)
void save(CaseDbTransaction transaction)
UNKNOWN
File marked as unknown by hash db.
Definition: TskData.java:800
TskData.CollectedStatus getCollected()
List< TskFileRange > convertToImgRanges(long fileOffset, long length)
void setLocalPath(String localPath, boolean isAbsolute)
static String createNonUniquePath(String uniquePath)
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:700
void addAttributes(Collection< Attribute > attributes, final SleuthkitCase.CaseDbTransaction caseDbTransaction)
final int read(byte[] buf, long offset, long len)
final TSK_FS_META_TYPE_ENUM metaType
int read(byte[] buf, long offset, long len)
List< TskFileRange > getFileRanges(long id)
TskData.TSK_FS_ATTR_TYPE_ENUM getAttrType()

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