19 package org.sleuthkit.datamodel;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.RandomAccessFile;
24 import java.lang.ref.SoftReference;
25 import java.sql.SQLException;
26 import java.sql.Statement;
27 import java.text.MessageFormat;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.List;
32 import java.util.Objects;
33 import java.util.Optional;
34 import java.util.ResourceBundle;
36 import java.util.SortedSet;
37 import java.util.TimeZone;
38 import java.util.logging.Level;
39 import java.util.logging.Logger;
61 protected final long metaAddr, ctime, crtime, atime, mtime;
63 protected final int uid, gid;
68 private boolean localPathSet =
false;
69 private String localPath;
70 private String localAbsPath;
71 private volatile RandomAccessFile localFileHandle;
72 private volatile java.io.File localFile;
75 private List<TskFileRange> ranges;
84 private boolean knownStateDirty =
false;
89 private boolean md5HashDirty =
false;
94 private boolean sha256HashDirty =
false;
100 private boolean sha1HashDirty =
false;
103 private boolean collectedDirty =
false;
105 private String mimeType;
106 private boolean mimeTypeDirty =
false;
108 private static final ResourceBundle BUNDLE = ResourceBundle.getBundle(
"org.sleuthkit.datamodel.Bundle");
109 private long dataSourceObjectId;
110 private final String extension;
111 private final List<Attribute> fileAttributesCache =
new ArrayList<Attribute>();
112 private boolean loadedAttributesCacheFromDb =
false;
114 private final String ownerUid;
117 private final Long osAccountObjId;
119 private volatile String uniquePath;
122 private final boolean tryContentProviderStream;
123 private Object contentProviderStreamLock =
new Object();
124 private SoftReference<ContentProviderStream> contentProviderStreamRef = null;
169 long dataSourceObjectId,
170 Long fileSystemObjectId,
174 long metaAddr,
int metaSeq,
178 long ctime,
long crtime,
long atime,
long mtime,
181 String md5Hash, String sha256Hash, String sha1Hash,
187 Long osAccountObjectId,
189 List<Attribute> fileAttributes) {
190 super(db, objId, name);
191 this.dataSourceObjectId = dataSourceObjectId;
192 if (fileSystemObjectId != null) {
195 if (fileSystemObjectId > 0) {
198 this.fileSystemObjectId = null;
201 this.fileSystemObjectId = null;
211 this.metaFlags = TSK_FS_META_FLAG_ENUM.valuesOf(metaFlags);
214 this.crtime = crtime;
219 this.modes = TskData.TSK_FS_META_MODE_ENUM.valuesOf(modes);
224 if (knownState == null) {
225 this.knownState = FileKnown.
UNKNOWN;
230 this.mimeType = mimeType;
231 this.extension = extension == null ?
"" : extension;
233 this.ownerUid = ownerUid;
234 this.osAccountObjId = osAccountObjectId;
235 this.collected = collected;
238 this.tryContentProviderStream = collected == CollectedStatus.YES_REPO && db.getContentProvider() != null;
239 if (Objects.nonNull(fileAttributes) && !fileAttributes.isEmpty()) {
240 this.fileAttributesCache.addAll(fileAttributes);
241 loadedAttributesCacheFromDb =
true;
410 if ((mode & irusr) == irusr) {
415 if ((mode & iwusr) == iwusr) {
422 if ((mode & isuid) == isuid) {
423 if ((mode & ixusr) == ixusr) {
429 if ((mode & ixusr) == ixusr) {
437 if ((mode & irgrp) == irgrp) {
442 if ((mode & iwgrp) == iwgrp) {
449 if ((mode & isgid) == isgid) {
450 if ((mode & ixgrp) == ixgrp) {
456 if ((mode & ixgrp) == ixgrp) {
464 if ((mode & iroth) == iroth) {
469 if ((mode & iwoth) == iwoth) {
476 if ((mode & isvtx) == isvtx) {
477 if ((mode & ixoth) == ixoth) {
483 if ((mode & ixoth) == ixoth) {
491 if (result.length() != 10) {
516 this.mimeType = mimeType;
517 this.mimeTypeDirty =
true;
521 return modes.contains(mode);
534 this.md5HashDirty =
true;
556 this.sha256HashDirty =
true;
578 this.sha1HashDirty =
true;
598 synchronized (
this) {
599 if (!loadedAttributesCacheFromDb) {
601 fileAttributesCache.clear();
602 fileAttributesCache.addAll(attributes);
603 loadedAttributesCacheFromDb =
true;
605 return Collections.unmodifiableList(fileAttributesCache);
624 if (Objects.isNull(attributes) || attributes.isEmpty()) {
625 throw new TskCoreException(
"Illegal Argument passed to addAttributes: null or empty attributes passed to addAttributes");
627 boolean isLocalTransaction = Objects.isNull(caseDbTransaction);
632 for (
final Attribute attribute : attributes) {
633 attribute.setAttributeParentId(
getId());
638 if (isLocalTransaction) {
639 localTransaction.commit();
640 localTransaction = null;
643 synchronized (
this) {
644 if (loadedAttributesCacheFromDb) {
645 fileAttributesCache.addAll(attributes);
648 }
catch (SQLException ex) {
649 if (isLocalTransaction && null != localTransaction) {
651 localTransaction.rollback();
652 }
catch (TskCoreException ex2) {
653 LOGGER.log(Level.SEVERE,
"Failed to rollback transaction after exception", ex2);
656 throw new TskCoreException(
"Error adding file attributes", ex);
672 if (this.knownState.compareTo(knownState) > 0) {
678 this.knownStateDirty =
true;
743 return dataSourceObjectId;
761 this.collected = collected;
762 collectedDirty =
true;
776 if (ranges == null) {
801 long rangeLength = byteRange.getByteLen();
802 if (fileOffset < rangeLength) {
803 imgOffset = byteRange.getByteStart() + fileOffset;
809 fileOffset -= rangeLength;
829 if (fileOffset < 0 || length < 0) {
833 List<TskFileRange> thisRanges =
getRanges();
834 List<TskFileRange> toRet =
new ArrayList<>();
836 long requestedEnd = fileOffset + length;
839 long bytesCounted = 0;
841 for (
int curRangeIdx = 0; curRangeIdx < thisRanges.size(); curRangeIdx++) {
843 if (bytesCounted >= requestedEnd) {
850 long curRangeEnd = bytesCounted + curRangeLen;
855 if (fileOffset < curRangeEnd) {
857 long rangeOffset = Math.max(0, fileOffset - bytesCounted);
860 long newRangeStart = curRange.
getByteStart() + rangeOffset;
863 long rangeOvershoot = Math.max(0, curRangeEnd - requestedEnd);
865 long newRangeLen = curRangeLen - rangeOffset - rangeOvershoot;
866 toRet.add(
new TskFileRange(newRangeStart, newRangeLen, toRet.size()));
869 bytesCounted = curRangeEnd;
917 public abstract boolean isRoot();
930 String[] pathSegments = uniquePath.split(
"/");
934 if (pathSegments[0].startsWith(
"img_")) {
937 if (pathSegments[1].startsWith(
"vol_")) {
943 StringBuilder strbuf =
new StringBuilder();
944 for (; index < pathSegments.length; ++index) {
945 if (!pathSegments[index].isEmpty()) {
946 strbuf.append(
"/").append(pathSegments[index]);
950 return strbuf.toString();
964 List<AbstractFile> files =
new ArrayList<AbstractFile>();
965 for (
Content child : children) {
967 AbstractFile afChild = (AbstractFile) child;
997 return dirType.toString();
1006 return dirFlag == flag;
1045 return metaFlags.contains(metaFlag);
1054 metaFlags.add(metaFlag);
1062 void removeMetaFlag(TSK_FS_META_FLAG_ENUM metaFlag) {
1063 metaFlags.remove(metaFlag);
1071 short getMetaFlagsAsInt() {
1072 return TSK_FS_META_FLAG_ENUM.toInt(metaFlags);
1086 private ContentProviderStream getContentProviderStream() throws TskCoreException {
1087 synchronized (contentProviderStreamLock) {
1089 ContentProviderStream contentProviderStream = contentProviderStreamRef == null ? null : contentProviderStreamRef.get();
1091 if (contentProviderStream == null) {
1093 contentProviderStream = provider == null ? null : provider.
getContentStream(
this).orElse(null);
1095 if (contentProviderStream == null) {
1096 throw new TskCoreException(MessageFormat.format(
"Could not get content provider string for file with obj id: {0}, path: {1}",
1101 this.contentProviderStreamRef =
new SoftReference<>(contentProviderStream);
1104 return contentProviderStream;
1109 public final int read(byte[] buf,
long offset,
long len)
throws TskCoreException {
1111 if (tryContentProviderStream) {
1113 return contentProviderStream.
read(buf, offset, len);
1114 }
else if (localPathSet) {
1118 return readInt(buf, offset, len);
1134 protected int readInt(byte[] buf,
long offset,
long len)
throws TskCoreException {
1149 protected final int readLocal(byte[] buf,
long offset,
long len)
throws TskCoreException {
1150 if (!localPathSet) {
1151 throw new TskCoreException(
1152 BUNDLE.getString(
"AbstractFile.readLocal.exception.msg1.text"));
1168 if (localFileHandle == null) {
1169 synchronized (
this) {
1170 if (localFileHandle == null) {
1172 localFileHandle =
new RandomAccessFile(localFile,
"r");
1173 }
catch (FileNotFoundException ex) {
1174 final String msg = MessageFormat.format(BUNDLE.getString(
1175 "AbstractFile.readLocal.exception.msg4.text"),
1177 LOGGER.log(Level.SEVERE, msg, ex);
1179 throw new TskCoreException(msg, ex);
1189 long encodedOffset = offset + EncodedFileUtil.getHeaderLength();
1192 long curOffset = localFileHandle.getFilePointer();
1193 if (curOffset != encodedOffset) {
1194 localFileHandle.seek(encodedOffset);
1196 bytesRead = localFileHandle.read(buf, 0, (
int) len);
1197 for (
int i = 0; i < bytesRead; i++) {
1198 buf[i] = EncodedFileUtil.decodeByte(buf[i], encodingType);
1203 long curOffset = localFileHandle.getFilePointer();
1204 if (curOffset != offset) {
1205 localFileHandle.seek(offset);
1208 return localFileHandle.read(buf, 0, (
int) len);
1210 }
catch (IOException ex) {
1211 final String msg = MessageFormat.format(BUNDLE.getString(
"AbstractFile.readLocal.exception.msg5.text"), localAbsPath);
1212 LOGGER.log(Level.SEVERE, msg, ex);
1214 throw new TskCoreException(msg, ex);
1225 void setLocalFilePath(String localPath) {
1227 if (localPath == null || localPath.equals(
"")) {
1228 this.localPath =
"";
1229 localAbsPath = null;
1230 localPathSet =
false;
1235 this.localPath = localPath;
1236 if (
this instanceof DerivedFile) {
1242 if (localPath.startsWith(
"/") || localPath.startsWith(
"\\")
1243 || localPath.matches(
"[A-Za-z]:[/\\\\].*")) {
1244 this.localAbsPath = localPath;
1249 this.localPathSet =
true;
1268 return localAbsPath;
1277 this.encodingType = encodingType;
1288 if (tryContentProviderStream || !localPathSet) {
1293 return localFile.
exists();
1294 }
catch (TskCoreException ex) {
1295 LOGGER.log(Level.SEVERE, ex.getMessage());
1309 if (tryContentProviderStream || !localPathSet) {
1315 }
catch (TskCoreException ex) {
1316 LOGGER.log(Level.SEVERE, ex.getMessage());
1328 private void loadLocalFile() throws TskCoreException {
1329 if (!localPathSet) {
1330 throw new TskCoreException(
1331 BUNDLE.getString(
"AbstractFile.readLocal.exception.msg1.text"));
1335 if (localFile != null) {
1339 synchronized (
this) {
1340 if (localFile == null) {
1341 localFile =
new java.io.File(localAbsPath);
1350 if (localFileHandle != null) {
1351 synchronized (
this) {
1352 if (localFileHandle != null) {
1354 localFileHandle.close();
1355 }
catch (IOException ex) {
1356 LOGGER.log(Level.SEVERE,
"Could not close file handle for file: " +
getParentPath() +
getName(), ex);
1358 localFileHandle = null;
1365 @SuppressWarnings(
"deprecation")
1377 return super.toString(preserveState) +
"AbstractFile [\t"
1379 +
"\tctime " + ctime
1380 +
"\tcrtime " + crtime
1381 +
"\t" +
"mtime " + mtime +
"\t" +
"atime " + atime
1382 +
"\t" +
"attrId " + attrId
1384 +
"\t" +
"dirFlag " + dirFlag +
"\t" +
"dirType " + dirType
1385 +
"\t" +
"uid " + uid
1386 +
"\t" +
"gid " + gid
1387 +
"\t" +
"metaAddr " + metaAddr +
"\t" +
"metaSeq " + metaSeq +
"\t" +
"metaFlags " + metaFlags
1388 +
"\t" +
"metaType " + metaType +
"\t" +
"modes " + modes
1389 +
"\t" +
"parentPath " + parentPath +
"\t" +
"size " + size
1390 +
"\t" +
"knownState " + knownState +
"\t" +
"md5Hash " + md5Hash +
"\t" +
"sha256Hash " + sha256Hash +
"\t" +
"sha1Hash " + sha1Hash
1391 +
"\t" +
"localPathSet " + localPathSet +
"\t" +
"localPath " + localPath
1392 +
"\t" +
"localAbsPath " + localAbsPath +
"\t" +
"localFile " + localFile
1415 if (this.mimeType == null) {
1418 if (mimeTypes.contains(
this.mimeType)) {
1431 public void save() throws TskCoreException {
1437 }
catch (TskCoreException ex) {
1438 if (transaction != null) {
1456 if (!(md5HashDirty || sha256HashDirty || sha1HashDirty || mimeTypeDirty || knownStateDirty || collectedDirty)) {
1460 String updateSql =
"";
1461 if (mimeTypeDirty) {
1462 updateSql =
"mime_type = '" + this.
getMIMEType() +
"'";
1465 if (!updateSql.isEmpty()) {
1468 updateSql +=
"md5 = '" + this.
getMd5Hash() +
"'";
1470 if (sha256HashDirty) {
1471 if (!updateSql.isEmpty()) {
1476 if (sha1HashDirty) {
1477 if (!updateSql.isEmpty()) {
1480 updateSql +=
"sha1 = '" + this.
getSha1Hash() +
"'";
1482 if (knownStateDirty) {
1483 if (!updateSql.isEmpty()) {
1486 updateSql +=
"known = '" + this.
getKnown().getFileKnownValue() +
"'";
1488 if (collectedDirty) {
1489 if (!updateSql.isEmpty()) {
1492 updateSql +=
"collected = '" + this.
getCollected().getType() +
"'";
1494 updateSql =
"UPDATE tsk_files SET " + updateSql +
" WHERE obj_id = " + this.
getId();
1497 try (Statement statement = connection.createStatement()) {
1498 connection.executeUpdate(statement, updateSql);
1499 md5HashDirty =
false;
1500 sha256HashDirty =
false;
1501 sha1HashDirty =
false;
1502 mimeTypeDirty =
false;
1503 knownStateDirty =
false;
1504 collectedDirty =
false;
1505 }
catch (SQLException ex) {
1506 throw new TskCoreException(String.format(
"Error updating properties of file %s (obj_id = %s)",
getName(),
getId()), ex);
1519 return Optional.ofNullable(ownerUid);
1528 return Optional.ofNullable(osAccountObjId);
1537 parentFileSystem = parent;
1546 return Optional.ofNullable(fileSystemObjectId);
1555 return fileSystemObjectId != null;
1570 if (fileSystemObjectId == null) {
1571 throw new TskCoreException(
"File with ID: " + this.
getId() +
" does not belong to a file system");
1573 if (parentFileSystem == null) {
1574 synchronized (
this) {
1575 if (parentFileSystem == null) {
1580 return parentFileSystem;
1594 if (uniquePath == null) {
1600 StringBuilder sb =
new StringBuilder();
1602 if (! parentPath.isEmpty()) {
1603 sb.append(parentPath);
1609 uniquePath = sb.toString();
1611 if ((
this instanceof
LayoutFile) && (parentPath.equals(
"/"))) {
1615 uniquePath = super.getUniquePath();
1621 uniquePath = super.getUniquePath();
1627 String dataSourceName =
"";
1629 if (dataSource != null) {
1632 if (! parentPath.isEmpty()) {
1633 uniquePath = dataSourceName + parentPath +
getName();
1636 uniquePath = dataSourceName +
"/" +
getName();
1645 @SuppressWarnings(
"deprecation")
1678 @SuppressWarnings(
"deprecation")
1705 setLocalFilePath(localPath);
1799 long dataSourceObjectId,
1800 Long fileSystemObjectId,
1804 long metaAddr,
int metaSeq,
1808 long ctime,
long crtime,
long atime,
long mtime,
1811 String md5Hash, String sha256Hash, String sha1Hash,
1817 Long osAccountObjectId,
1818 List<Attribute> fileAttributes) {
1819 this(db, objId, dataSourceObjectId,
fileSystemObjectId,
attrType,
attrId, name,
fileType,
metaAddr,
metaSeq,
1820 dirType,
metaType,
dirFlag,
metaFlags,
size, ctime, crtime, atime, mtime,
modes,
uid, gid,
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()
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()