19 package org.sleuthkit.datamodel;
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;
37 import java.util.SortedSet;
38 import java.util.TimeZone;
39 import java.util.logging.Level;
40 import java.util.logging.Logger;
62 protected final long metaAddr, ctime, crtime, atime, mtime;
64 protected final int uid, gid;
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;
76 private List<TskFileRange> ranges;
85 private boolean knownStateDirty =
false;
90 private boolean md5HashDirty =
false;
95 private boolean sha256HashDirty =
false;
101 private boolean sha1HashDirty =
false;
104 private boolean collectedDirty =
false;
106 private String mimeType;
107 private boolean mimeTypeDirty =
false;
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;
115 private final String ownerUid;
118 private final Long osAccountObjId;
120 private volatile String uniquePath;
123 private final boolean tryContentProviderStream;
124 private Object contentProviderStreamLock =
new Object();
125 private SoftReference<ContentProviderStream> contentProviderStreamRef = null;
170 long dataSourceObjectId,
171 Long fileSystemObjectId,
175 long metaAddr,
int metaSeq,
179 long ctime,
long crtime,
long atime,
long mtime,
182 String md5Hash, String sha256Hash, String sha1Hash,
188 Long osAccountObjectId,
190 List<Attribute> fileAttributes) {
191 super(db, objId, name);
192 this.dataSourceObjectId = dataSourceObjectId;
193 if (fileSystemObjectId != null) {
196 if (fileSystemObjectId > 0) {
199 this.fileSystemObjectId = null;
202 this.fileSystemObjectId = null;
212 this.metaFlags = TSK_FS_META_FLAG_ENUM.valuesOf(metaFlags);
215 this.crtime = crtime;
220 this.modes = TskData.TSK_FS_META_MODE_ENUM.valuesOf(modes);
225 if (knownState == null) {
226 this.knownState = FileKnown.
UNKNOWN;
231 this.mimeType = mimeType;
232 this.extension = extension == null ?
"" : extension;
234 this.ownerUid = ownerUid;
235 this.osAccountObjId = osAccountObjectId;
236 this.collected = collected;
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;
411 if ((mode & irusr) == irusr) {
416 if ((mode & iwusr) == iwusr) {
423 if ((mode & isuid) == isuid) {
424 if ((mode & ixusr) == ixusr) {
430 if ((mode & ixusr) == ixusr) {
438 if ((mode & irgrp) == irgrp) {
443 if ((mode & iwgrp) == iwgrp) {
450 if ((mode & isgid) == isgid) {
451 if ((mode & ixgrp) == ixgrp) {
457 if ((mode & ixgrp) == ixgrp) {
465 if ((mode & iroth) == iroth) {
470 if ((mode & iwoth) == iwoth) {
477 if ((mode & isvtx) == isvtx) {
478 if ((mode & ixoth) == ixoth) {
484 if ((mode & ixoth) == ixoth) {
492 if (result.length() != 10) {
517 this.mimeType = mimeType;
518 this.mimeTypeDirty =
true;
522 return modes.contains(mode);
535 this.md5HashDirty =
true;
557 this.sha256HashDirty =
true;
579 this.sha1HashDirty =
true;
599 synchronized (
this) {
600 if (!loadedAttributesCacheFromDb) {
602 fileAttributesCache.clear();
603 fileAttributesCache.addAll(attributes);
604 loadedAttributesCacheFromDb =
true;
606 return Collections.unmodifiableList(fileAttributesCache);
625 if (Objects.isNull(attributes) || attributes.isEmpty()) {
626 throw new TskCoreException(
"Illegal Argument passed to addAttributes: null or empty attributes passed to addAttributes");
628 boolean isLocalTransaction = Objects.isNull(caseDbTransaction);
633 for (
final Attribute attribute : attributes) {
634 attribute.setAttributeParentId(
getId());
639 if (isLocalTransaction) {
640 localTransaction.commit();
641 localTransaction = null;
644 synchronized (
this) {
645 if (loadedAttributesCacheFromDb) {
646 fileAttributesCache.addAll(attributes);
649 }
catch (SQLException ex) {
650 if (isLocalTransaction && null != localTransaction) {
652 localTransaction.rollback();
653 }
catch (TskCoreException ex2) {
654 LOGGER.log(Level.SEVERE,
"Failed to rollback transaction after exception", ex2);
657 throw new TskCoreException(
"Error adding file attributes", ex);
673 if (this.knownState.compareTo(knownState) > 0) {
679 this.knownStateDirty =
true;
744 return dataSourceObjectId;
762 this.collected = collected;
763 collectedDirty =
true;
777 if (ranges == null) {
802 long rangeLength = byteRange.getByteLen();
803 if (fileOffset < rangeLength) {
804 imgOffset = byteRange.getByteStart() + fileOffset;
810 fileOffset -= rangeLength;
830 if (fileOffset < 0 || length < 0) {
834 List<TskFileRange> thisRanges =
getRanges();
835 List<TskFileRange> toRet =
new ArrayList<>();
837 long requestedEnd = fileOffset + length;
840 long bytesCounted = 0;
842 for (
int curRangeIdx = 0; curRangeIdx < thisRanges.size(); curRangeIdx++) {
844 if (bytesCounted >= requestedEnd) {
851 long curRangeEnd = bytesCounted + curRangeLen;
856 if (fileOffset < curRangeEnd) {
858 long rangeOffset = Math.max(0, fileOffset - bytesCounted);
861 long newRangeStart = curRange.
getByteStart() + rangeOffset;
864 long rangeOvershoot = Math.max(0, curRangeEnd - requestedEnd);
866 long newRangeLen = curRangeLen - rangeOffset - rangeOvershoot;
867 toRet.add(
new TskFileRange(newRangeStart, newRangeLen, toRet.size()));
870 bytesCounted = curRangeEnd;
939 public abstract boolean isRoot();
952 String[] pathSegments = uniquePath.split(
"/");
956 if (pathSegments[0].startsWith(
"img_")) {
959 if (pathSegments[1].startsWith(
"vol_")) {
965 StringBuilder strbuf =
new StringBuilder();
966 for (; index < pathSegments.length; ++index) {
967 if (!pathSegments[index].isEmpty()) {
968 strbuf.append(
"/").append(pathSegments[index]);
972 return strbuf.toString();
986 List<AbstractFile> files =
new ArrayList<AbstractFile>();
987 for (
Content child : children) {
989 AbstractFile afChild = (AbstractFile) child;
1019 return dirType.toString();
1028 return dirFlag == flag;
1067 return metaFlags.contains(metaFlag);
1076 metaFlags.add(metaFlag);
1084 void removeMetaFlag(TSK_FS_META_FLAG_ENUM metaFlag) {
1085 metaFlags.remove(metaFlag);
1093 short getMetaFlagsAsInt() {
1094 return TSK_FS_META_FLAG_ENUM.toInt(metaFlags);
1108 private ContentProviderStream getContentProviderStream() throws TskCoreException {
1109 synchronized (contentProviderStreamLock) {
1111 ContentProviderStream contentProviderStream = contentProviderStreamRef == null ? null : contentProviderStreamRef.get();
1113 if (contentProviderStream == null) {
1115 contentProviderStream = provider == null ? null : provider.
getContentStream(
this).orElse(null);
1117 if (contentProviderStream == null) {
1118 throw new TskCoreException(MessageFormat.format(
"Could not get content provider string for file with obj id: {0}, path: {1}",
1123 this.contentProviderStreamRef =
new SoftReference<>(contentProviderStream);
1126 return contentProviderStream;
1131 public final int read(byte[] buf,
long offset,
long len)
throws TskCoreException {
1133 if (tryContentProviderStream) {
1135 return contentProviderStream.
read(buf, offset, len);
1136 }
else if (localPathSet) {
1140 return readInt(buf, offset, len);
1156 protected int readInt(byte[] buf,
long offset,
long len)
throws TskCoreException {
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"));
1190 if (localFileHandle == null) {
1191 synchronized (
this) {
1192 if (localFileHandle == null) {
1194 localFileHandle =
new RandomAccessFile(localFile,
"r");
1195 }
catch (FileNotFoundException ex) {
1196 final String msg = MessageFormat.format(BUNDLE.getString(
1197 "AbstractFile.readLocal.exception.msg4.text"),
1199 LOGGER.log(Level.SEVERE, msg, ex);
1201 throw new TskCoreException(msg, ex);
1211 long encodedOffset = offset + EncodedFileUtil.getHeaderLength();
1214 long curOffset = localFileHandle.getFilePointer();
1215 if (curOffset != encodedOffset) {
1216 localFileHandle.seek(encodedOffset);
1218 bytesRead = localFileHandle.read(buf, 0, (
int) len);
1219 for (
int i = 0; i < bytesRead; i++) {
1220 buf[i] = EncodedFileUtil.decodeByte(buf[i], encodingType);
1225 long curOffset = localFileHandle.getFilePointer();
1226 if (curOffset != offset) {
1227 localFileHandle.seek(offset);
1230 return localFileHandle.read(buf, 0, (
int) len);
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);
1236 throw new TskCoreException(msg, ex);
1247 void setLocalFilePath(String localPath) {
1249 if (localPath == null || localPath.equals(
"")) {
1250 this.localPath =
"";
1251 localAbsPath = null;
1252 localPathSet =
false;
1257 this.localPath = localPath;
1258 if (
this instanceof DerivedFile) {
1264 if (localPath.startsWith(
"/") || localPath.startsWith(
"\\")
1265 || localPath.matches(
"[A-Za-z]:[/\\\\].*")) {
1266 this.localAbsPath = localPath;
1271 this.localPathSet =
true;
1290 return localAbsPath;
1299 this.encodingType = encodingType;
1310 if (tryContentProviderStream || !localPathSet) {
1315 return localFile.
exists();
1316 }
catch (TskCoreException ex) {
1317 LOGGER.log(Level.SEVERE, ex.getMessage());
1331 if (tryContentProviderStream || !localPathSet) {
1337 }
catch (TskCoreException ex) {
1338 LOGGER.log(Level.SEVERE, ex.getMessage());
1350 private void loadLocalFile() throws TskCoreException {
1351 if (!localPathSet) {
1352 throw new TskCoreException(
1353 BUNDLE.getString(
"AbstractFile.readLocal.exception.msg1.text"));
1357 if (localFile != null) {
1361 synchronized (
this) {
1362 if (localFile == null) {
1363 localFile =
new java.io.File(localAbsPath);
1372 if (localFileHandle != null) {
1373 synchronized (
this) {
1374 if (localFileHandle != null) {
1376 localFileHandle.close();
1377 }
catch (IOException ex) {
1378 LOGGER.log(Level.SEVERE,
"Could not close file handle for file: " +
getParentPath() +
getName(), ex);
1380 localFileHandle = null;
1387 @SuppressWarnings(
"deprecation")
1399 return super.toString(preserveState) +
"AbstractFile [\t"
1401 +
"\tctime " + ctime
1402 +
"\tcrtime " + crtime
1403 +
"\t" +
"mtime " + mtime +
"\t" +
"atime " + atime
1404 +
"\t" +
"attrId " + attrId
1406 +
"\t" +
"dirFlag " + dirFlag +
"\t" +
"dirType " + dirType
1407 +
"\t" +
"uid " + uid
1408 +
"\t" +
"gid " + gid
1409 +
"\t" +
"metaAddr " + metaAddr +
"\t" +
"metaSeq " + metaSeq +
"\t" +
"metaFlags " + metaFlags
1410 +
"\t" +
"metaType " + metaType +
"\t" +
"modes " + modes
1411 +
"\t" +
"parentPath " + parentPath +
"\t" +
"size " + size
1412 +
"\t" +
"knownState " + knownState +
"\t" +
"md5Hash " + md5Hash +
"\t" +
"sha256Hash " + sha256Hash +
"\t" +
"sha1Hash " + sha1Hash
1413 +
"\t" +
"localPathSet " + localPathSet +
"\t" +
"localPath " + localPath
1414 +
"\t" +
"localAbsPath " + localAbsPath +
"\t" +
"localFile " + localFile
1437 if (this.mimeType == null) {
1440 if (mimeTypes.contains(
this.mimeType)) {
1453 public void save() throws TskCoreException {
1459 }
catch (TskCoreException ex) {
1460 if (transaction != null) {
1478 if (!(md5HashDirty || sha256HashDirty || sha1HashDirty || mimeTypeDirty || knownStateDirty || collectedDirty)) {
1482 String updateSql =
"";
1483 if (mimeTypeDirty) {
1484 updateSql =
"mime_type = '" + this.
getMIMEType() +
"'";
1487 if (!updateSql.isEmpty()) {
1490 updateSql +=
"md5 = '" + this.
getMd5Hash() +
"'";
1492 if (sha256HashDirty) {
1493 if (!updateSql.isEmpty()) {
1498 if (sha1HashDirty) {
1499 if (!updateSql.isEmpty()) {
1502 updateSql +=
"sha1 = '" + this.
getSha1Hash() +
"'";
1504 if (knownStateDirty) {
1505 if (!updateSql.isEmpty()) {
1508 updateSql +=
"known = '" + this.
getKnown().getFileKnownValue() +
"'";
1510 if (collectedDirty) {
1511 if (!updateSql.isEmpty()) {
1514 updateSql +=
"collected = '" + this.
getCollected().getType() +
"'";
1516 updateSql =
"UPDATE tsk_files SET " + updateSql +
" WHERE obj_id = " + this.
getId();
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);
1541 return Optional.ofNullable(ownerUid);
1550 return Optional.ofNullable(osAccountObjId);
1559 parentFileSystem = parent;
1568 return Optional.ofNullable(fileSystemObjectId);
1577 return fileSystemObjectId != null;
1592 if (fileSystemObjectId == null) {
1593 throw new TskCoreException(
"File with ID: " + this.
getId() +
" does not belong to a file system");
1595 if (parentFileSystem == null) {
1596 synchronized (
this) {
1597 if (parentFileSystem == null) {
1602 return parentFileSystem;
1616 if (uniquePath == null) {
1622 StringBuilder sb =
new StringBuilder();
1624 if (! parentPath.isEmpty()) {
1625 sb.append(parentPath);
1631 uniquePath = sb.toString();
1633 if ((
this instanceof
LayoutFile) && (parentPath.equals(
"/"))) {
1637 uniquePath = super.getUniquePath();
1643 uniquePath = super.getUniquePath();
1649 String dataSourceName =
"";
1651 if (dataSource != null) {
1654 if (! parentPath.isEmpty()) {
1655 uniquePath = dataSourceName + parentPath +
getName();
1658 uniquePath = dataSourceName +
"/" +
getName();
1667 @SuppressWarnings(
"deprecation")
1700 @SuppressWarnings(
"deprecation")
1727 setLocalFilePath(localPath);
1821 long dataSourceObjectId,
1822 Long fileSystemObjectId,
1826 long metaAddr,
int metaSeq,
1830 long ctime,
long crtime,
long atime,
long mtime,
1833 String md5Hash, String sha256Hash, String sha1Hash,
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,
VIRT
Special (TSK added "Virtual" files) NON-NLS.
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)
String getMetaFlagsAsString()
CaseDbTransaction beginTransaction()
final int readLocal(byte[] buf, long offset, long len)
boolean isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM flag)
List< Content > getChildren()
ALLOC
Metadata structure is currently in an allocated state.
final Long fileSystemObjectId
Blackboard getBlackboard()
TSK_FS_META_TYPE_DIR
Directory file NON-NLS.
void setMIMEType(String mimeType)
void setSha256Hash(String sha256Hash)
TSK_FS_META_MODE_ISVTX
sticky bit
final TskData.TSK_DB_FILES_TYPE_ENUM fileType
UNALLOC
Metadata structure is currently in an unallocated state.
TskData.TSK_DB_FILES_TYPE_ENUM getType()
final TskData.TSK_FS_ATTR_TYPE_ENUM attrType
TSK_FS_META_MODE_IXOTH
X for other.
TSK_FS_META_TYPE_VIRT_DIR
"Virtual Directory" created by TSK for Orphan Files NON-NLS
long convertToImgOffset(long fileOffset)
TSK_FS_META_MODE_ISUID
set user id on execution
TSK_FS_NAME_TYPE_ENUM getDirType()
Content getContentById(long id)
String getDirFlagAsString()
TSK_FS_META_MODE_IXGRP
X for group.
String getNameExtension()
int countChildrenOfType(List< TSK_FS_NAME_TYPE_ENUM > types)
List< Attribute > getAttributes()
static final String NAME_CARVED
TSK_FS_META_MODE_IWOTH
W for other.
BlackboardArtifact newArtifact(int artifactTypeID)
TSK_FS_META_MODE_IRGRP
R for group.
long getDataSourceObjectId()
TSK_FS_NAME_FLAG_ENUM dirFlag
TSK_FS_META_MODE_IWUSR
W for owner.
MimeMatchEnum isMimeType(SortedSet< String > mimeTypes)
String getDirTypeAsString()
void setCollected(TskData.CollectedStatus collected)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, Collection< BlackboardAttribute > attributesList)
TSK_FS_META_MODE_IROTH
R for other.
String toString(boolean preserveState)
Set< TSK_FS_META_FLAG_ENUM > metaFlags
TskData.FileKnown getKnown()
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
List< AbstractFile > listFiles()
TskData.FileKnown knownState
TSK_FS_META_TYPE_VIRT
"Virtual File" created by TSK for file system areas NON-NLS
TSK_FS_META_TYPE_ENUM getMetaType()
TSK_FS_META_MODE_IRUSR
R for owner.
SleuthkitCase getSleuthkitCase()
boolean equals(Object obj)
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)
Optional< ContentProviderStream > getContentStream(Content content)
static String epochToTime(long epoch, TimeZone tzone)
static long timeToEpoch(String time)
String getModesAsString()
static final String NAME_UNALLOC
int readInt(byte[] buf, long offset, long len)
Optional< String > getOwnerUid()
Optional< Long > getFileSystemObjectId()
void save(CaseDbTransaction transaction)
UNKNOWN
File marked as unknown by hash db.
TskData.CollectedStatus getCollected()
List< TskFileRange > convertToImgRanges(long fileOffset, long length)
void setLocalPath(String localPath, boolean isAbsolute)
void setMd5Hash(String md5Hash)
static String createNonUniquePath(String uniquePath)
TSK_FS_META_MODE_IWGRP
W for group.
VIRTUAL_DIR
Virtual directory (not on fs) with no meta-data entry that can be used to group files of types other ...
void addAttributes(Collection< Attribute > attributes, final SleuthkitCase.CaseDbTransaction caseDbTransaction)
List< TskFileRange > getRanges()
final int read(byte[] buf, long offset, long len)
String getMetaTypeAsString()
final TSK_FS_META_TYPE_ENUM metaType
static final long UNKNOWN_ID
TSK_FS_META_TYPE_REG
Regular file NON-NLS.
TSK_FS_META_MODE_ISGID
set group id on execution
int read(byte[] buf, long offset, long len)
List< TskFileRange > getFileRanges(long id)
TSK_FS_META_MODE_IXUSR
X for owner.
TskData.TSK_FS_ATTR_TYPE_ENUM getAttrType()
void setSha1Hash(String sha1Hash)
FileSystem getFileSystem()
abstract boolean isRoot()
Optional< Long > getOsAccountObjectId()