Sleuth Kit Java Bindings (JNI)  4.11.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.sql.SQLException;
25 import java.sql.Statement;
26 import java.text.MessageFormat;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.List;
31 import java.util.Objects;
32 import java.util.Optional;
33 import java.util.ResourceBundle;
34 import java.util.Set;
35 import java.util.SortedSet;
36 import java.util.TimeZone;
37 import java.util.logging.Level;
38 import java.util.logging.Logger;
45 
50 public abstract class AbstractFile extends AbstractContent {
51 
53  protected final TSK_FS_NAME_TYPE_ENUM dirType;
56  protected Set<TSK_FS_META_FLAG_ENUM> metaFlags;
57  protected final Long fileSystemObjectId; // File system object ID; may be null
58  protected long size;
59  protected final long metaAddr, ctime, crtime, atime, mtime;
60  protected final int metaSeq;
61  protected final int uid, gid;
62  protected final int attrId;
64  protected final Set<TskData.TSK_FS_META_MODE_ENUM> modes;
65  //local file support
66  private boolean localPathSet = false;
67  private String localPath;
68  private String localAbsPath;
69  private volatile RandomAccessFile localFileHandle;
70  private volatile java.io.File localFile;
71  private TskData.EncodingType encodingType;
72  //range support
73  private List<TskFileRange> ranges;
74  /*
75  * path of parent directory
76  */
77  protected final String parentPath;
82  private boolean knownStateDirty = false;
83  /*
84  * md5 hash
85  */
86  protected String md5Hash;
87  private boolean md5HashDirty = false;
88  /*
89  * SHA-256 hash
90  */
91  protected String sha256Hash;
92  private boolean sha256HashDirty = false;
93 
94  /*
95  * SHA-1 hash
96  */
97  protected String sha1Hash;
98  private boolean sha1HashDirty = false;
99 
100  private String mimeType;
101  private boolean mimeTypeDirty = false;
102  private static final Logger LOGGER = Logger.getLogger(AbstractFile.class.getName());
103  private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle");
104  private long dataSourceObjectId;
105  private final String extension;
106  private final List<Attribute> fileAttributesCache = new ArrayList<Attribute>();
107  private boolean loadedAttributesCacheFromDb = false;
108 
109  private final String ownerUid; // string owner uid, for example a Windows SID.
110  // different from the numeric uid which is more commonly found
111  // on Unix based file systems.
112  private final Long osAccountObjId; // obj id of the owner's OS account, may be null
113 
114  private volatile String uniquePath;
115  private volatile FileSystem parentFileSystem;
116 
158  long objId,
159  long dataSourceObjectId,
160  Long fileSystemObjectId,
162  String name,
164  long metaAddr, int metaSeq,
166  TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags,
167  long size,
168  long ctime, long crtime, long atime, long mtime,
169  short modes,
170  int uid, int gid,
171  String md5Hash, String sha256Hash, String sha1Hash,
173  String parentPath,
174  String mimeType,
175  String extension,
176  String ownerUid,
177  Long osAccountObjectId,
178  List<Attribute> fileAttributes) {
179  super(db, objId, name);
180  this.dataSourceObjectId = dataSourceObjectId;
181  if (fileSystemObjectId != null) {
182  // When reading from the result set, nulls are converted to zeros.
183  // Switch it to null.
184  if (fileSystemObjectId > 0) {
185  this.fileSystemObjectId = fileSystemObjectId;
186  } else {
187  this.fileSystemObjectId = null;
188  }
189  } else {
190  this.fileSystemObjectId = null;
191  }
192  this.attrType = attrType;
193  this.attrId = attrId;
194  this.fileType = fileType;
195  this.metaAddr = metaAddr;
196  this.metaSeq = metaSeq;
197  this.dirType = dirType;
198  this.metaType = metaType;
199  this.dirFlag = dirFlag;
200  this.metaFlags = TSK_FS_META_FLAG_ENUM.valuesOf(metaFlags);
201  this.size = size;
202  this.ctime = ctime;
203  this.crtime = crtime;
204  this.atime = atime;
205  this.mtime = mtime;
206  this.uid = uid;
207  this.gid = gid;
208  this.modes = TskData.TSK_FS_META_MODE_ENUM.valuesOf(modes);
209 
210  this.md5Hash = md5Hash;
211  this.sha256Hash = sha256Hash;
212  this.sha1Hash = sha1Hash;
213  if (knownState == null) {
214  this.knownState = FileKnown.UNKNOWN;
215  } else {
216  this.knownState = knownState;
217  }
218  this.parentPath = parentPath;
219  this.mimeType = mimeType;
220  this.extension = extension == null ? "" : extension;
221  this.encodingType = TskData.EncodingType.NONE;
222  this.ownerUid = ownerUid;
223  this.osAccountObjId = osAccountObjectId;
224  if (Objects.nonNull(fileAttributes) && !fileAttributes.isEmpty()) {
225  this.fileAttributesCache.addAll(fileAttributes);
226  loadedAttributesCacheFromDb = true;
227  }
228  }
229 
236  return fileType;
237  }
238 
245  return attrType;
246  }
247 
253  public int getAttributeId() {
254  return attrId;
255  }
256 
262  public long getCtime() {
263  return ctime;
264  }
265 
271  public String getCtimeAsDate() {
272  return epochToTime(ctime);
273  }
274 
280  public long getCrtime() {
281  return crtime;
282  }
283 
289  public String getCrtimeAsDate() {
290  return epochToTime(crtime);
291  }
292 
298  public long getAtime() {
299  return atime;
300  }
301 
307  public String getAtimeAsDate() {
308  return epochToTime(atime);
309  }
310 
316  public long getMtime() {
317  return mtime;
318  }
319 
325  public String getMtimeAsDate() {
326  return epochToTime(mtime);
327  }
328 
334  public int getUid() {
335  return uid;
336  }
337 
343  public int getGid() {
344  return gid;
345  }
346 
352  public long getMetaAddr() {
353  return metaAddr;
354  }
355 
362  public long getMetaSeq() {
363  return metaSeq;
364  }
365 
371  public String getModesAsString() {
373  String result = "";
374 
375  short isuid = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_ISUID.getMode();
376  short isgid = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_ISGID.getMode();
377  short isvtx = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_ISVTX.getMode();
378 
379  short irusr = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IRUSR.getMode();
380  short iwusr = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IWUSR.getMode();
381  short ixusr = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IXUSR.getMode();
382 
383  short irgrp = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IRGRP.getMode();
384  short iwgrp = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IWGRP.getMode();
385  short ixgrp = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IXGRP.getMode();
386 
387  short iroth = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IROTH.getMode();
388  short iwoth = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IWOTH.getMode();
389  short ixoth = TskData.TSK_FS_META_MODE_ENUM.TSK_FS_META_MODE_IXOTH.getMode();
390 
391  // first character = the Meta Type
392  result += metaType.toString();
393 
394  // second and third characters = user permissions
395  if ((mode & irusr) == irusr) {
396  result += "r"; //NON-NLS
397  } else {
398  result += "-"; //NON-NLS
399  }
400  if ((mode & iwusr) == iwusr) {
401  result += "w"; //NON-NLS
402  } else {
403  result += "-"; //NON-NLS
404  }
405 
406  // fourth character = set uid
407  if ((mode & isuid) == isuid) {
408  if ((mode & ixusr) == ixusr) {
409  result += "s"; //NON-NLS
410  } else {
411  result += "S"; //NON-NLS
412  }
413  } else {
414  if ((mode & ixusr) == ixusr) {
415  result += "x"; //NON-NLS
416  } else {
417  result += "-"; //NON-NLS
418  }
419  }
420 
421  // fifth and sixth characters = group permissions
422  if ((mode & irgrp) == irgrp) {
423  result += "r"; //NON-NLS
424  } else {
425  result += "-"; //NON-NLS
426  }
427  if ((mode & iwgrp) == iwgrp) {
428  result += "w"; //NON-NLS
429  } else {
430  result += "-"; //NON-NLS
431  }
432 
433  // seventh character = set gid
434  if ((mode & isgid) == isgid) {
435  if ((mode & ixgrp) == ixgrp) {
436  result += "s"; //NON-NLS
437  } else {
438  result += "S"; //NON-NLS
439  }
440  } else {
441  if ((mode & ixgrp) == ixgrp) {
442  result += "x"; //NON-NLS
443  } else {
444  result += "-"; //NON-NLS
445  }
446  }
447 
448  // eighth and ninth character = other permissions
449  if ((mode & iroth) == iroth) {
450  result += "r"; //NON-NLS
451  } else {
452  result += "-"; //NON-NLS
453  }
454  if ((mode & iwoth) == iwoth) {
455  result += "w"; //NON-NLS
456  } else {
457  result += "-"; //NON-NLS
458  }
459 
460  // tenth character = sticky bit
461  if ((mode & isvtx) == isvtx) {
462  if ((mode & ixoth) == ixoth) {
463  result += "t"; //NON-NLS
464  } else {
465  result += "T"; //NON-NLS
466  }
467  } else {
468  if ((mode & ixoth) == ixoth) {
469  result += "x"; //NON-NLS
470  } else {
471  result += "-"; //NON-NLS
472  }
473  }
474 
475  // check the result
476  if (result.length() != 10) {
477  // throw error here
478  result = "ERROR"; //NON-NLS
479  }
480  return result;
481  }
482 
488  public String getMIMEType() {
489  return mimeType;
490  }
491 
500  public void setMIMEType(String mimeType) {
501  this.mimeType = mimeType;
502  this.mimeTypeDirty = true;
503  }
504 
505  public boolean isModeSet(TskData.TSK_FS_META_MODE_ENUM mode) {
506  return modes.contains(mode);
507  }
508 
517  public void setMd5Hash(String md5Hash) {
518  this.md5Hash = md5Hash;
519  this.md5HashDirty = true;
520  }
521 
527  public String getMd5Hash() {
528  return this.md5Hash;
529  }
530 
539  public void setSha256Hash(String sha256Hash) {
540  this.sha256Hash = sha256Hash;
541  this.sha256HashDirty = true;
542  }
543 
549  public String getSha256Hash() {
550  return this.sha256Hash;
551  }
552 
561  public void setSha1Hash(String sha1Hash) {
562  this.sha1Hash = sha1Hash;
563  this.sha1HashDirty = true;
564  }
565 
571  public String getSha1Hash() {
572  return this.sha1Hash;
573  }
574 
582  public List<Attribute> getAttributes() throws TskCoreException {
583  synchronized (this) {
584  if (!loadedAttributesCacheFromDb) {
585  ArrayList<Attribute> attributes = getSleuthkitCase().getBlackboard().getFileAttributes(this);
586  fileAttributesCache.clear();
587  fileAttributesCache.addAll(attributes);
588  loadedAttributesCacheFromDb = true;
589  }
590  return Collections.unmodifiableList(fileAttributesCache);
591  }
592  }
593 
607  public void addAttributes(Collection<Attribute> attributes, final SleuthkitCase.CaseDbTransaction caseDbTransaction) throws TskCoreException {
608 
609  if (Objects.isNull(attributes) || attributes.isEmpty()) {
610  throw new TskCoreException("Illegal Argument passed to addAttributes: null or empty attributes passed to addAttributes");
611  }
612  boolean isLocalTransaction = Objects.isNull(caseDbTransaction);
613  SleuthkitCase.CaseDbTransaction localTransaction = isLocalTransaction ? getSleuthkitCase().beginTransaction() : null;
614  SleuthkitCase.CaseDbConnection connection = isLocalTransaction ? localTransaction.getConnection() : caseDbTransaction.getConnection();
615 
616  try {
617  for (final Attribute attribute : attributes) {
618  attribute.setAttributeParentId(getId());
619  attribute.setCaseDatabase(getSleuthkitCase());
620  getSleuthkitCase().addFileAttribute(attribute, connection);
621  }
622 
623  if (isLocalTransaction) {
624  localTransaction.commit();
625  localTransaction = null;
626  }
627  // append the new attributes if cache is already loaded.
628  synchronized (this) {
629  if (loadedAttributesCacheFromDb) {
630  fileAttributesCache.addAll(attributes);
631  }
632  }
633  } catch (SQLException ex) {
634  if (isLocalTransaction && null != localTransaction) {
635  try {
636  localTransaction.rollback();
637  } catch (TskCoreException ex2) {
638  LOGGER.log(Level.SEVERE, "Failed to rollback transaction after exception", ex2);
639  }
640  }
641  throw new TskCoreException("Error adding file attributes", ex);
642  }
643  }
644 
656  // don't allow them to downgrade the known state
657  if (this.knownState.compareTo(knownState) > 0) {
658  // ideally we'd return some kind of error, but
659  // the API doesn't allow it
660  return;
661  }
662  this.knownState = knownState;
663  this.knownStateDirty = true;
664  }
665 
673  return knownState;
674  }
675 
683  public String getNameExtension() {
684  return extension;
685  }
686 
692  @Override
693  public long getSize() {
694  return size;
695  }
696 
702  public String getParentPath() {
703  return parentPath;
704  }
705 
717  @Override
719  return getSleuthkitCase().getContentById(this.dataSourceObjectId);
720  }
721 
727  public long getDataSourceObjectId() {
728  return dataSourceObjectId;
729  }
730 
741  public List<TskFileRange> getRanges() throws TskCoreException {
742  if (ranges == null) {
743  ranges = getSleuthkitCase().getFileRanges(this.getId());
744  }
745  return ranges;
746  }
747 
761  public long convertToImgOffset(long fileOffset) throws TskCoreException {
762  long imgOffset = -1;
763  for (TskFileRange byteRange : getRanges()) {
764 
765  // if fileOffset is within the current byteRange, calculate the image
766  // offset and break
767  long rangeLength = byteRange.getByteLen();
768  if (fileOffset < rangeLength) {
769  imgOffset = byteRange.getByteStart() + fileOffset;
770  break;
771  }
772 
773  // otherwise, decrement fileOffset by the length of the current
774  // byte range and continue
775  fileOffset -= rangeLength;
776  }
777  return imgOffset;
778  }
779 
794  public List<TskFileRange> convertToImgRanges(long fileOffset, long length) throws TskCoreException {
795  if (fileOffset < 0 || length < 0) {
796  throw new TskCoreException("fileOffset and length must be non-negative");
797  }
798 
799  List<TskFileRange> thisRanges = getRanges();
800  List<TskFileRange> toRet = new ArrayList<>();
801 
802  long requestedEnd = fileOffset + length;
803 
804  // the number of bytes counted from the beginning of this file
805  long bytesCounted = 0;
806 
807  for (int curRangeIdx = 0; curRangeIdx < thisRanges.size(); curRangeIdx++) {
808  // if we exceeded length of requested, then we are done
809  if (bytesCounted >= requestedEnd) {
810  break;
811  }
812 
813  TskFileRange curRange = thisRanges.get(curRangeIdx);
814  long curRangeLen = curRange.getByteLen();
815  // the bytes counted when we reach the end of this range
816  long curRangeEnd = bytesCounted + curRangeLen;
817 
818  // if fileOffset is less than current range's end and we have not
819  // gone past the end we requested, then grab at least part of this
820  // range.
821  if (fileOffset < curRangeEnd) {
822  // offset into range to be returned to user (0 if fileOffset <= bytesCounted)
823  long rangeOffset = Math.max(0, fileOffset - bytesCounted);
824 
825  // calculate the new TskFileRange start by adding on the offset into the current range
826  long newRangeStart = curRange.getByteStart() + rangeOffset;
827 
828  // how much this current range exceeds the length requested (or 0 if within the length requested)
829  long rangeOvershoot = Math.max(0, curRangeEnd - requestedEnd);
830 
831  long newRangeLen = curRangeLen - rangeOffset - rangeOvershoot;
832  toRet.add(new TskFileRange(newRangeStart, newRangeLen, toRet.size()));
833  }
834 
835  bytesCounted = curRangeEnd;
836  }
837 
838  return toRet;
839  }
840 
847  public boolean isVirtual() {
849  || dirType.equals(TskData.TSK_FS_NAME_TYPE_ENUM.VIRT)
851  }
852 
860  public boolean isFile() {
861  return metaType.equals(TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG)
862  || (metaType.equals(TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_UNDEF)
863  && dirType.equals(TSK_FS_NAME_TYPE_ENUM.REG));
864 
865  }
866 
873  public boolean isDir() {
874  return (metaType.equals(TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR)
876  }
877 
883  public abstract boolean isRoot();
884 
893  public static String createNonUniquePath(String uniquePath) {
894 
895  // split the path into parts
896  String[] pathSegments = uniquePath.split("/");
897 
898  // see if uniquePath had an image and/or volume name
899  int index = 0;
900  if (pathSegments[0].startsWith("img_")) { //NON-NLS
901  ++index;
902  }
903  if (pathSegments[1].startsWith("vol_")) { //NON-NLS
904  ++index;
905  }
906 
907  // Assemble the non-unique path (skipping over the image and volume
908  // name, if they exist).
909  StringBuilder strbuf = new StringBuilder();
910  for (; index < pathSegments.length; ++index) {
911  if (!pathSegments[index].isEmpty()) {
912  strbuf.append("/").append(pathSegments[index]);
913  }
914  }
915 
916  return strbuf.toString();
917  }
918 
925  public List<AbstractFile> listFiles() throws TskCoreException {
926  // first, get all children
927  List<Content> children = getChildren();
928 
929  // only keep those that are of type AbstractFile
930  List<AbstractFile> files = new ArrayList<AbstractFile>();
931  for (Content child : children) {
932  if (child instanceof AbstractFile) {
933  AbstractFile afChild = (AbstractFile) child;
934  files.add(afChild);
935  }
936  }
937  return files;
938  }
939 
946  return metaType;
947  }
948 
949  public String getMetaTypeAsString() {
950  return metaType.toString();
951  }
952 
959  return dirType;
960  }
961 
962  public String getDirTypeAsString() {
963  return dirType.toString();
964  }
965 
972  return dirFlag == flag;
973  }
974 
979  public String getDirFlagAsString() {
980  return dirFlag.toString();
981  }
982 
988  void setDirFlag(TSK_FS_NAME_FLAG_ENUM flag) {
989  dirFlag = flag;
990  }
991 
995  public String getMetaFlagsAsString() {
996  String str = "";
997  if (metaFlags.contains(TSK_FS_META_FLAG_ENUM.ALLOC)) {
998  str = TSK_FS_META_FLAG_ENUM.ALLOC.toString();
999  } else if (metaFlags.contains(TSK_FS_META_FLAG_ENUM.UNALLOC)) {
1000  str = TSK_FS_META_FLAG_ENUM.UNALLOC.toString();
1001  }
1002  return str;
1003  }
1004 
1010  public boolean isMetaFlagSet(TSK_FS_META_FLAG_ENUM metaFlag) {
1011  return metaFlags.contains(metaFlag);
1012  }
1013 
1019  void setMetaFlag(TSK_FS_META_FLAG_ENUM metaFlag) {
1020  metaFlags.add(metaFlag);
1021  }
1022 
1028  void removeMetaFlag(TSK_FS_META_FLAG_ENUM metaFlag) {
1029  metaFlags.remove(metaFlag);
1030  }
1031 
1037  short getMetaFlagsAsInt() {
1038  return TSK_FS_META_FLAG_ENUM.toInt(metaFlags);
1039  }
1040 
1041  @Override
1042  public final int read(byte[] buf, long offset, long len) throws TskCoreException {
1043  //template method
1044  //if localPath is set, use local, otherwise, use readCustom() supplied by derived class
1045  if (localPathSet) {
1046  return readLocal(buf, offset, len);
1047  } else {
1048  return readInt(buf, offset, len);
1049  }
1050 
1051  }
1052 
1064  protected int readInt(byte[] buf, long offset, long len) throws TskCoreException {
1065  return 0;
1066  }
1067 
1079  protected final int readLocal(byte[] buf, long offset, long len) throws TskCoreException {
1080  if (!localPathSet) {
1081  throw new TskCoreException(
1082  BUNDLE.getString("AbstractFile.readLocal.exception.msg1.text"));
1083  }
1084 
1085  if (isDir()) {
1086  return 0;
1087  }
1088 
1089  // If the file is empty, just return that zero bytes were read.
1090  if (getSize() == 0) {
1091  return 0;
1092  }
1093 
1094  loadLocalFile();
1095 
1096  int bytesRead = 0;
1097 
1098  if (localFileHandle == null) {
1099  synchronized (this) {
1100  if (localFileHandle == null) {
1101  try {
1102  localFileHandle = new RandomAccessFile(localFile, "r");
1103  } catch (FileNotFoundException ex) {
1104  final String msg = MessageFormat.format(BUNDLE.getString(
1105  "AbstractFile.readLocal.exception.msg4.text"),
1106  localAbsPath);
1107  LOGGER.log(Level.SEVERE, msg, ex);
1108  //file could have been deleted or moved
1109  throw new TskCoreException(msg, ex);
1110  }
1111  }
1112  }
1113  }
1114 
1115  try {
1116  if (!encodingType.equals(TskData.EncodingType.NONE)) {
1117  // The file is encoded, so we need to alter the offset to read (since there's
1118  // a header on the encoded file) and then decode each byte
1119  long encodedOffset = offset + EncodedFileUtil.getHeaderLength();
1120 
1121  //move to the user request offset in the stream
1122  long curOffset = localFileHandle.getFilePointer();
1123  if (curOffset != encodedOffset) {
1124  localFileHandle.seek(encodedOffset);
1125  }
1126  bytesRead = localFileHandle.read(buf, 0, (int) len);
1127  for (int i = 0; i < bytesRead; i++) {
1128  buf[i] = EncodedFileUtil.decodeByte(buf[i], encodingType);
1129  }
1130  return bytesRead;
1131  } else {
1132  //move to the user request offset in the stream
1133  long curOffset = localFileHandle.getFilePointer();
1134  if (curOffset != offset) {
1135  localFileHandle.seek(offset);
1136  }
1137  //note, we are always writing at 0 offset of user buffer
1138  return localFileHandle.read(buf, 0, (int) len);
1139  }
1140  } catch (IOException ex) {
1141  final String msg = MessageFormat.format(BUNDLE.getString("AbstractFile.readLocal.exception.msg5.text"), localAbsPath);
1142  LOGGER.log(Level.SEVERE, msg, ex);
1143  //local file could have been deleted / moved
1144  throw new TskCoreException(msg, ex);
1145  }
1146  }
1147 
1155  void setLocalFilePath(String localPath) {
1156 
1157  if (localPath == null || localPath.equals("")) {
1158  this.localPath = "";
1159  localAbsPath = null;
1160  localPathSet = false;
1161  } else {
1162  // It should always be the case that absolute paths start with slashes or a windows drive letter
1163  // and relative paths do not, but some older versions of modules created derived file paths
1164  // starting with slashes. So we first check if this file is a DerivedFile before looking at the path.
1165  this.localPath = localPath;
1166  if (this instanceof DerivedFile) {
1167  // DerivedFiles always have relative paths
1168  this.localAbsPath = getSleuthkitCase().getDbDirPath() + java.io.File.separator + localPath;
1169  } else {
1170  // If a path starts with a slash or with a Windows drive letter, then it is
1171  // absolute. Otherwise it is relative.
1172  if (localPath.startsWith("/") || localPath.startsWith("\\")
1173  || localPath.matches("[A-Za-z]:[/\\\\].*")) {
1174  this.localAbsPath = localPath;
1175  } else {
1176  this.localAbsPath = getSleuthkitCase().getDbDirPath() + java.io.File.separator + localPath;
1177  }
1178  }
1179  this.localPathSet = true;
1180  }
1181  }
1182 
1188  public String getLocalPath() {
1189  return localPath;
1190  }
1191 
1197  public String getLocalAbsPath() {
1198  return localAbsPath;
1199  }
1200 
1206  final void setEncodingType(TskData.EncodingType encodingType) {
1207  this.encodingType = encodingType;
1208  }
1209 
1216  public boolean exists() {
1217  if (!localPathSet) {
1218  return true;
1219  } else {
1220  try {
1221  loadLocalFile();
1222  return localFile.exists();
1223  } catch (TskCoreException ex) {
1224  LOGGER.log(Level.SEVERE, ex.getMessage());
1225  return false;
1226  }
1227  }
1228  }
1229 
1237  public boolean canRead() {
1238  if (!localPathSet) {
1239  return true;
1240  } else {
1241  try {
1242  loadLocalFile();
1243  return localFile.canRead();
1244  } catch (TskCoreException ex) {
1245  LOGGER.log(Level.SEVERE, ex.getMessage());
1246  return false;
1247  }
1248  }
1249  }
1250 
1257  private void loadLocalFile() throws TskCoreException {
1258  if (!localPathSet) {
1259  throw new TskCoreException(
1260  BUNDLE.getString("AbstractFile.readLocal.exception.msg1.text"));
1261  }
1262 
1263  // already been set
1264  if (localFile != null) {
1265  return;
1266  }
1267 
1268  synchronized (this) {
1269  if (localFile == null) {
1270  localFile = new java.io.File(localAbsPath);
1271  }
1272  }
1273  }
1274 
1275  @Override
1276  public void close() {
1277 
1278  //close local file handle if set
1279  if (localFileHandle != null) {
1280  synchronized (this) {
1281  if (localFileHandle != null) {
1282  try {
1283  localFileHandle.close();
1284  } catch (IOException ex) {
1285  LOGGER.log(Level.SEVERE, "Could not close file handle for file: " + getParentPath() + getName(), ex); //NON-NLS
1286  }
1287  localFileHandle = null;
1288  }
1289  }
1290  }
1291 
1292  }
1293 
1294  @SuppressWarnings("deprecation")
1295  @Override
1296  protected void finalize() throws Throwable {
1297  try {
1298  close();
1299  } finally {
1300  super.finalize();
1301  }
1302  }
1303 
1304  @Override
1305  public String toString(boolean preserveState) {
1306  return super.toString(preserveState) + "AbstractFile [\t" //NON-NLS
1307  + "\t" + "fileType " + fileType //NON-NLS
1308  + "\tctime " + ctime //NON-NLS
1309  + "\tcrtime " + crtime //NON-NLS
1310  + "\t" + "mtime " + mtime + "\t" + "atime " + atime //NON-NLS
1311  + "\t" + "attrId " + attrId //NON-NLS
1312  + "\t" + "attrType " + attrType //NON-NLS
1313  + "\t" + "dirFlag " + dirFlag + "\t" + "dirType " + dirType //NON-NLS
1314  + "\t" + "uid " + uid //NON-NLS
1315  + "\t" + "gid " + gid //NON-NLS
1316  + "\t" + "metaAddr " + metaAddr + "\t" + "metaSeq " + metaSeq + "\t" + "metaFlags " + metaFlags //NON-NLS
1317  + "\t" + "metaType " + metaType + "\t" + "modes " + modes //NON-NLS
1318  + "\t" + "parentPath " + parentPath + "\t" + "size " + size //NON-NLS
1319  + "\t" + "knownState " + knownState + "\t" + "md5Hash " + md5Hash + "\t" + "sha256Hash " + sha256Hash + "\t" + "sha1Hash " + sha1Hash//NON-NLS
1320  + "\t" + "localPathSet " + localPathSet + "\t" + "localPath " + localPath //NON-NLS
1321  + "\t" + "localAbsPath " + localAbsPath + "\t" + "localFile " + localFile //NON-NLS
1322  + "]\t";
1323  }
1324 
1328  public enum MimeMatchEnum {
1329 
1332  FALSE
1333  }
1334 
1343  public MimeMatchEnum isMimeType(SortedSet<String> mimeTypes) {
1344  if (this.mimeType == null) {
1345  return MimeMatchEnum.UNDEFINED;
1346  }
1347  if (mimeTypes.contains(this.mimeType)) {
1348  return MimeMatchEnum.TRUE;
1349  }
1350  return MimeMatchEnum.FALSE;
1351  }
1352 
1360  public void save() throws TskCoreException {
1361  CaseDbTransaction transaction = null;
1362  try {
1363  transaction = getSleuthkitCase().beginTransaction();
1364  save(transaction);
1365  transaction.commit();
1366  } catch (TskCoreException ex) {
1367  if (transaction != null) {
1368  transaction.rollback();
1369  }
1370  throw ex;
1371  }
1372  }
1373 
1384  public void save(CaseDbTransaction transaction) throws TskCoreException {
1385  if (!(md5HashDirty || sha256HashDirty || sha1HashDirty || mimeTypeDirty || knownStateDirty)) {
1386  return;
1387  }
1388 
1389  String updateSql = "";
1390  if (mimeTypeDirty) {
1391  updateSql = "mime_type = '" + this.getMIMEType() + "'";
1392  }
1393  if (md5HashDirty) {
1394  if (!updateSql.isEmpty()) {
1395  updateSql += ", ";
1396  }
1397  updateSql += "md5 = '" + this.getMd5Hash() + "'";
1398  }
1399  if (sha256HashDirty) {
1400  if (!updateSql.isEmpty()) {
1401  updateSql += ", ";
1402  }
1403  updateSql += "sha256 = '" + this.getSha256Hash() + "'";
1404  }
1405  if (sha1HashDirty) {
1406  if (!updateSql.isEmpty()) {
1407  updateSql += ", ";
1408  }
1409  updateSql += "sha1 = '" + this.getSha1Hash() + "'";
1410  }
1411  if (knownStateDirty) {
1412  if (!updateSql.isEmpty()) {
1413  updateSql += ", ";
1414  }
1415  updateSql += "known = '" + this.getKnown().getFileKnownValue() + "'";
1416  }
1417  updateSql = "UPDATE tsk_files SET " + updateSql + " WHERE obj_id = " + this.getId();
1418 
1419  SleuthkitCase.CaseDbConnection connection = transaction.getConnection();
1420  try (Statement statement = connection.createStatement()) {
1421  connection.executeUpdate(statement, updateSql);
1422  md5HashDirty = false;
1423  sha256HashDirty = false;
1424  sha1HashDirty = false;
1425  mimeTypeDirty = false;
1426  knownStateDirty = false;
1427  } catch (SQLException ex) {
1428  throw new TskCoreException(String.format("Error updating properties of file %s (obj_id = %s)", getName(), getId()), ex);
1429  }
1430  }
1431 
1440  public Optional<String> getOwnerUid() {
1441  return Optional.ofNullable(ownerUid);
1442  }
1443 
1449  public Optional<Long> getOsAccountObjectId() {
1450  return Optional.ofNullable(osAccountObjId);
1451  }
1452 
1458  void setFileSystem(FileSystem parent) {
1459  parentFileSystem = parent;
1460  }
1461 
1467  public Optional<Long> getFileSystemObjectId() {
1468  return Optional.ofNullable(fileSystemObjectId);
1469  }
1470 
1476  public boolean hasFileSystem() {
1477  return fileSystemObjectId != null;
1478  }
1479 
1491  public FileSystem getFileSystem() throws TskCoreException {
1492  if (fileSystemObjectId == null) {
1493  throw new TskCoreException("File with ID: " + this.getId() + " does not belong to a file system");
1494  }
1495  if (parentFileSystem == null) {
1496  synchronized (this) {
1497  if (parentFileSystem == null) {
1498  parentFileSystem = getSleuthkitCase().getFileSystemById(fileSystemObjectId, AbstractContent.UNKNOWN_ID);
1499  }
1500  }
1501  }
1502  return parentFileSystem;
1503  }
1504 
1513  @Override
1514  public String getUniquePath() throws TskCoreException {
1515 
1516  if (uniquePath == null) {
1517  if (getFileSystemObjectId().isPresent()) {
1518  // For file system files, construct the path using the path to
1519  // the file system, the parent path, and the file name. FileSystem
1520  // objects are cached so this is unlikely to perform any
1521  // database operations.
1522  StringBuilder sb = new StringBuilder();
1523  sb.append(getFileSystem().getUniquePath());
1524  if (! parentPath.isEmpty()) {
1525  sb.append(parentPath);
1526  } else {
1527  // The parent path may not be set in older cases.
1528  sb.append("/");
1529  }
1530  sb.append(getName());
1531  uniquePath = sb.toString();
1532  } else {
1533  if ((this instanceof LayoutFile) && (parentPath.equals("/"))) {
1534  // This may be the case where the layout file is a direct child of a
1535  // volume. We want to make sure to include the volume information if present,
1536  // so go up the directory structure instead of using the optimized code.
1537  uniquePath = super.getUniquePath();
1539  parentPath.startsWith("/" + VirtualDirectory.NAME_CARVED) || parentPath.startsWith("/" + VirtualDirectory.NAME_UNALLOC)) {
1540  // We can make $Unalloc and $CarvedFiles under volumes without being part of a file system.
1541  // As above, we want to make sure to include the volume information if present,
1542  // so go up the directory structure instead of using the optimized code.
1543  uniquePath = super.getUniquePath();
1544  } else {
1545  // Optimized code to use for most files. Construct the path
1546  // using the data source name, the parent path, and the file name.
1547  // DataSource objects are cached so this is unlikely to perform any
1548  // database operations.
1549  String dataSourceName = "";
1550  Content dataSource = getDataSource();
1551  if (dataSource != null) {
1552  dataSourceName = dataSource.getUniquePath();
1553  }
1554  if (! parentPath.isEmpty()) {
1555  uniquePath = dataSourceName + parentPath + getName();
1556  } else {
1557  // The parent path may not be set in older cases.
1558  uniquePath = dataSourceName + "/" + getName();
1559  }
1560  }
1561  }
1562  }
1563  return uniquePath;
1564  }
1565 
1566  @Deprecated
1567  @SuppressWarnings("deprecation")
1568  @Override
1569  public BlackboardArtifact newArtifact(int artifactTypeID) throws TskCoreException {
1570  return super.newArtifact(artifactTypeID);
1571  }
1572 
1586  @Override
1587  public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection<BlackboardAttribute> attributesList) throws TskCoreException {
1588  return super.newDataArtifact(artifactType, attributesList, getOsAccountObjectId().orElse(null));
1589  }
1590 
1599  @Deprecated
1600  @SuppressWarnings("deprecation")
1601  public short getAttrId() {
1602  /*
1603  * NOTE: previously attrId used to be stored in AbstractFile as (signed)
1604  * short even though it is stored as uint16 in TSK. In extremely rare
1605  * occurrences attrId can be larger than what a signed short can hold
1606  * (2^15). Changes were made to AbstractFile to store attrId as integer.
1607  * Therefore this method has been deprecated. For backwards
1608  * compatibility, attribute ids that are larger than 32K are converted
1609  * to a negative number.
1610  */
1611  return (short) attrId; // casting to signed short converts values over 32K to negative values
1612  }
1613 
1625  @Deprecated
1626  protected void setLocalPath(String localPath, boolean isAbsolute) {
1627  setLocalFilePath(localPath);
1628  }
1629 
1630  /*
1631  * -------------------------------------------------------------------------
1632  * Util methods to convert / map the data
1633  * -------------------------------------------------------------------------
1634  */
1644  @Deprecated
1645  public static String epochToTime(long epoch) {
1646  return TimeUtilities.epochToTime(epoch);
1647  }
1648 
1660  @Deprecated
1661  public static String epochToTime(long epoch, TimeZone tzone) {
1662  return TimeUtilities.epochToTime(epoch, tzone);
1663  }
1664 
1672  @Deprecated
1673  public static long timeToEpoch(String time) {
1674  return TimeUtilities.timeToEpoch(time);
1675  }
1676 }
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)
static Set< TSK_FS_META_FLAG_ENUM > valuesOf(short metaFlags)
Definition: TskData.java:247
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:206
void setSha256Hash(String sha256Hash)
final TskData.TSK_DB_FILES_TYPE_ENUM fileType
UNALLOC
Metadata structure is currently in an unallocated state.
Definition: TskData.java:207
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)
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:422
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:793
static Set< TSK_FS_META_MODE_ENUM > valuesOf(short modes)
Definition: TskData.java:403
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:693
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
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.