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 com.google.common.annotations.Beta;
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24 import java.io.RandomAccessFile;
25 import java.lang.ref.SoftReference;
26 import java.sql.SQLException;
27 import java.sql.Statement;
28 import java.text.MessageFormat;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.Objects;
34 import java.util.Optional;
35 import java.util.ResourceBundle;
36 import java.util.Set;
37 import java.util.SortedSet;
38 import java.util.TimeZone;
39 import java.util.logging.Level;
40 import java.util.logging.Logger;
48 
53 public abstract class AbstractFile extends AbstractContent {
54 
56  protected final TSK_FS_NAME_TYPE_ENUM dirType;
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 
169  long objId,
170  long dataSourceObjectId,
171  Long fileSystemObjectId,
173  String name,
175  long metaAddr, int metaSeq,
177  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags,
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 
261  return attrType;
262  }
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() {
388  int mode = TskData.TSK_FS_META_MODE_ENUM.toInt(modes);
389  String result = "";
390 
391  short isuid = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_ISUID.getMode();
392  short isgid = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_ISGID.getMode();
393  short isvtx = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_ISVTX.getMode();
394 
395  short irusr = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IRUSR.getMode();
396  short iwusr = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IWUSR.getMode();
397  short ixusr = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IXUSR.getMode();
398 
399  short irgrp = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IRGRP.getMode();
400  short iwgrp = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IWGRP.getMode();
401  short ixgrp = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IXGRP.getMode();
402 
403  short iroth = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IROTH.getMode();
404  short iwoth = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IWOTH.getMode();
405  short ixoth = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IXOTH.getMode();
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 
521  public boolean isModeSet(TskData.TSK_FS_META_MODE_ENUM mode) {
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 
671  public void setKnown(TskData.FileKnown knownState) {
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 
882  public boolean isVirtual() {
884  || dirType.equals(TskData.TSK_FS_NAME_TYPE_ENUM.VIRT)
886  }
887 
895  public boolean isFile() {
896  return metaType.equals(TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG)
897  || (metaType.equals(TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_UNDEF)
898  && dirType.equals(TSK_FS_NAME_TYPE_ENUM.REG));
899 
900  }
901 
908  public boolean isDir() {
909  return (metaType.equals(TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR)
911  }
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 
1421  public enum MimeMatchEnum {
1422 
1425  FALSE
1426  }
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 
1591  public FileSystem getFileSystem() throws TskCoreException {
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,
1827  TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType,
1828  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags,
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,
1834  FileKnown knownState,
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,
1842  dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid,
1843  md5Hash, sha256Hash, sha1Hash, knownState, parentPath, mimeType, extension,
1844  ownerUid, osAccountObjectId, TskData.CollectedStatus.UNKNOWN, fileAttributes);
1845  }
1846 }
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()
int countChildrenOfType(List< TSK_FS_NAME_TYPE_ENUM > types)
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:428
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:802
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:701
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-2024 Brian Carrier. (carrier -at- sleuthkit -dot- org)
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.