19 package org.sleuthkit.datamodel;
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;
35 import java.util.SortedSet;
36 import java.util.TimeZone;
37 import java.util.logging.Level;
38 import java.util.logging.Logger;
58 protected final long metaAddr, ctime, crtime, atime, mtime;
60 protected final int uid, gid;
65 private boolean localPathSet =
false;
66 private String localPath;
67 private String localAbsPath;
68 private volatile RandomAccessFile localFileHandle;
69 private volatile java.io.File localFile;
72 private List<TskFileRange> ranges;
81 private boolean knownStateDirty =
false;
86 private boolean md5HashDirty =
false;
91 private boolean sha256HashDirty =
false;
92 private String mimeType;
93 private boolean mimeTypeDirty =
false;
95 private static final ResourceBundle BUNDLE = ResourceBundle.getBundle(
"org.sleuthkit.datamodel.Bundle");
96 private long dataSourceObjectId;
97 private final String extension;
98 private final List<Attribute> fileAttributesCache =
new ArrayList<Attribute>();
99 private boolean loadedAttributesCacheFromDb =
false;
101 private final String ownerUid;
104 private final Long osAccountObjId;
106 private volatile String uniquePath;
150 long dataSourceObjectId,
154 long metaAddr,
int metaSeq,
158 long ctime,
long crtime,
long atime,
long mtime,
166 Long osAccountObjectId,
167 List<Attribute> fileAttributes) {
168 super(db, objId, name);
169 this.dataSourceObjectId = dataSourceObjectId;
181 this.crtime = crtime;
190 if (knownState == null) {
196 this.mimeType = mimeType;
197 this.extension = extension == null ?
"" : extension;
199 this.ownerUid = ownerUid;
200 this.osAccountObjId = osAccountObjectId;
201 if (Objects.nonNull(fileAttributes) && !fileAttributes.isEmpty()) {
202 this.fileAttributesCache.addAll(fileAttributes);
203 loadedAttributesCacheFromDb =
true;
372 if ((mode & irusr) == irusr) {
377 if ((mode & iwusr) == iwusr) {
384 if ((mode & isuid) == isuid) {
385 if ((mode & ixusr) == ixusr) {
391 if ((mode & ixusr) == ixusr) {
399 if ((mode & irgrp) == irgrp) {
404 if ((mode & iwgrp) == iwgrp) {
411 if ((mode & isgid) == isgid) {
412 if ((mode & ixgrp) == ixgrp) {
418 if ((mode & ixgrp) == ixgrp) {
426 if ((mode & iroth) == iroth) {
431 if ((mode & iwoth) == iwoth) {
438 if ((mode & isvtx) == isvtx) {
439 if ((mode & ixoth) == ixoth) {
445 if ((mode & ixoth) == ixoth) {
453 if (result.length() != 10) {
478 this.mimeType = mimeType;
479 this.mimeTypeDirty =
true;
483 return modes.contains(mode);
496 this.md5HashDirty =
true;
518 this.sha256HashDirty =
true;
538 synchronized (
this) {
539 if (!loadedAttributesCacheFromDb) {
540 ArrayList<Attribute> attributes =
getSleuthkitCase().getFileAttributes(
this);
541 fileAttributesCache.clear();
542 fileAttributesCache.addAll(attributes);
543 loadedAttributesCacheFromDb =
true;
545 return Collections.unmodifiableList(fileAttributesCache);
564 if (Objects.isNull(attributes) || attributes.isEmpty()) {
565 throw new TskCoreException(
"Illegal Argument passed to addAttributes: null or empty attributes passed to addAttributes");
567 boolean isLocalTransaction = Objects.isNull(caseDbTransaction);
572 for (
final Attribute attribute : attributes) {
573 attribute.setAttributeParentId(
getId());
578 if (isLocalTransaction) {
579 localTransaction.commit();
580 localTransaction = null;
583 synchronized (
this) {
584 if (loadedAttributesCacheFromDb) {
585 fileAttributesCache.addAll(attributes);
588 }
catch (SQLException ex) {
589 if (isLocalTransaction && null != localTransaction) {
591 localTransaction.rollback();
592 }
catch (TskCoreException ex2) {
593 LOGGER.log(Level.SEVERE,
"Failed to rollback transaction after exception", ex2);
596 throw new TskCoreException(
"Error adding file attributes", ex);
618 this.knownStateDirty =
true;
683 return dataSourceObjectId;
697 if (ranges == null) {
722 long rangeLength = byteRange.getByteLen();
723 if (fileOffset < rangeLength) {
724 imgOffset = byteRange.getByteStart() + fileOffset;
730 fileOffset -= rangeLength;
750 if (fileOffset < 0 || length < 0) {
754 List<TskFileRange> thisRanges =
getRanges();
755 List<TskFileRange> toRet =
new ArrayList<>();
757 long requestedEnd = fileOffset + length;
760 long bytesCounted = 0;
762 for (
int curRangeIdx = 0; curRangeIdx < thisRanges.size(); curRangeIdx++) {
764 if (bytesCounted >= requestedEnd) {
771 long curRangeEnd = bytesCounted + curRangeLen;
776 if (fileOffset < curRangeEnd) {
778 long rangeOffset = Math.max(0, fileOffset - bytesCounted);
781 long newRangeStart = curRange.
getByteStart() + rangeOffset;
784 long rangeOvershoot = Math.max(0, curRangeEnd - requestedEnd);
786 long newRangeLen = curRangeLen - rangeOffset - rangeOvershoot;
787 toRet.add(
new TskFileRange(newRangeStart, newRangeLen, toRet.size()));
790 bytesCounted = curRangeEnd;
838 public abstract boolean isRoot();
851 String[] pathSegments = uniquePath.split(
"/");
855 if (pathSegments[0].startsWith(
"img_")) {
858 if (pathSegments[1].startsWith(
"vol_")) {
864 StringBuilder strbuf =
new StringBuilder();
865 for (; index < pathSegments.length; ++index) {
866 if (!pathSegments[index].isEmpty()) {
867 strbuf.append(
"/").append(pathSegments[index]);
871 return strbuf.toString();
885 List<AbstractFile> files =
new ArrayList<AbstractFile>();
886 for (
Content child : children) {
888 AbstractFile afChild = (AbstractFile) child;
918 return dirType.toString();
927 return dirFlag == flag;
966 return metaFlags.contains(metaFlag);
975 metaFlags.add(metaFlag);
983 void removeMetaFlag(TSK_FS_META_FLAG_ENUM metaFlag) {
984 metaFlags.remove(metaFlag);
992 short getMetaFlagsAsInt() {
993 return TSK_FS_META_FLAG_ENUM.toInt(metaFlags);
1003 return readInt(buf, offset, len);
1035 if (!localPathSet) {
1037 BUNDLE.getString(
"AbstractFile.readLocal.exception.msg1.text"));
1053 if (localFileHandle == null) {
1054 synchronized (
this) {
1055 if (localFileHandle == null) {
1057 localFileHandle =
new RandomAccessFile(localFile,
"r");
1058 }
catch (FileNotFoundException ex) {
1059 final String msg = MessageFormat.format(BUNDLE.getString(
1060 "AbstractFile.readLocal.exception.msg4.text"),
1062 LOGGER.log(Level.SEVERE, msg, ex);
1074 long encodedOffset = offset + EncodedFileUtil.getHeaderLength();
1077 long curOffset = localFileHandle.getFilePointer();
1078 if (curOffset != encodedOffset) {
1079 localFileHandle.seek(encodedOffset);
1081 bytesRead = localFileHandle.read(buf, 0, (
int) len);
1082 for (
int i = 0; i < bytesRead; i++) {
1083 buf[i] = EncodedFileUtil.decodeByte(buf[i], encodingType);
1088 long curOffset = localFileHandle.getFilePointer();
1089 if (curOffset != offset) {
1090 localFileHandle.seek(offset);
1093 return localFileHandle.read(buf, 0, (
int) len);
1095 }
catch (IOException ex) {
1096 final String msg = MessageFormat.format(BUNDLE.getString(
"AbstractFile.readLocal.exception.msg5.text"), localAbsPath);
1097 LOGGER.log(Level.SEVERE, msg, ex);
1110 void setLocalFilePath(String localPath) {
1112 if (localPath == null || localPath.equals(
"")) {
1113 this.localPath =
"";
1114 localAbsPath = null;
1115 localPathSet =
false;
1120 this.localPath = localPath;
1121 if (
this instanceof DerivedFile) {
1127 if (localPath.startsWith(
"/") || localPath.startsWith(
"\\")
1128 || localPath.matches(
"[A-Za-z]:[/\\\\].*")) {
1129 this.localAbsPath = localPath;
1134 this.localPathSet =
true;
1153 return localAbsPath;
1162 this.encodingType = encodingType;
1172 if (!localPathSet) {
1177 return localFile.
exists();
1179 LOGGER.log(Level.SEVERE, ex.getMessage());
1193 if (!localPathSet) {
1200 LOGGER.log(Level.SEVERE, ex.getMessage());
1213 if (!localPathSet) {
1214 throw new TskCoreException(
1215 BUNDLE.getString(
"AbstractFile.readLocal.exception.msg1.text"));
1219 if (localFile != null) {
1223 synchronized (
this) {
1224 if (localFile == null) {
1225 localFile =
new java.io.File(localAbsPath);
1234 if (localFileHandle != null) {
1235 synchronized (
this) {
1236 if (localFileHandle != null) {
1238 localFileHandle.close();
1239 }
catch (IOException ex) {
1240 LOGGER.log(Level.SEVERE,
"Could not close file handle for file: " +
getParentPath() +
getName(), ex);
1242 localFileHandle = null;
1260 return super.toString(preserveState) +
"AbstractFile [\t"
1262 +
"\tctime " + ctime
1263 +
"\tcrtime " + crtime
1264 +
"\t" +
"mtime " + mtime +
"\t" +
"atime " + atime
1265 +
"\t" +
"attrId " + attrId
1267 +
"\t" +
"dirFlag " + dirFlag +
"\t" +
"dirType " + dirType
1268 +
"\t" +
"uid " + uid
1269 +
"\t" +
"gid " + gid
1270 +
"\t" +
"metaAddr " + metaAddr +
"\t" +
"metaSeq " + metaSeq +
"\t" +
"metaFlags " + metaFlags
1271 +
"\t" +
"metaType " + metaType +
"\t" +
"modes " +
modes
1272 +
"\t" +
"parentPath " + parentPath +
"\t" +
"size " + size
1273 +
"\t" +
"knownState " +
knownState +
"\t" +
"md5Hash " + md5Hash +
"\t" +
"sha256Hash " + sha256Hash
1274 +
"\t" +
"localPathSet " + localPathSet +
"\t" +
"localPath " + localPath
1275 +
"\t" +
"localAbsPath " + localAbsPath +
"\t" +
"localFile " + localFile
1298 if (this.mimeType == null) {
1301 if (mimeTypes.contains(
this.mimeType)) {
1314 public void save() throws TskCoreException {
1320 }
catch (TskCoreException ex) {
1321 if (transaction != null) {
1339 if (!(md5HashDirty || sha256HashDirty || mimeTypeDirty || knownStateDirty)) {
1343 String updateSql =
"";
1344 if (mimeTypeDirty) {
1345 updateSql =
"mime_type = '" + this.
getMIMEType() +
"'";
1348 if (!updateSql.isEmpty()) {
1351 updateSql +=
"md5 = '" + this.
getMd5Hash() +
"'";
1353 if (sha256HashDirty) {
1354 if (!updateSql.isEmpty()) {
1359 if (knownStateDirty) {
1360 if (!updateSql.isEmpty()) {
1363 updateSql +=
"known = '" + this.
getKnown().getFileKnownValue() +
"'";
1365 updateSql =
"UPDATE tsk_files SET " + updateSql +
" WHERE obj_id = " + this.
getId();
1368 try (Statement statement = connection.createStatement()) {
1369 connection.executeUpdate(statement, updateSql);
1370 md5HashDirty =
false;
1371 sha256HashDirty =
false;
1372 mimeTypeDirty =
false;
1373 knownStateDirty =
false;
1374 }
catch (SQLException ex) {
1375 throw new TskCoreException(String.format(
"Error updating properties of file %s (obj_id = %s)",
getName(),
getId()), ex);
1388 return Optional.ofNullable(ownerUid);
1397 return Optional.ofNullable(osAccountObjId);
1403 if (uniquePath == null) {
1406 if(dataSource !=
this) {
1412 uniquePath = super.getUniquePath();
1420 @SuppressWarnings(
"deprecation")
1476 @SuppressWarnings(
"deprecation")
1480 long size,
long ctime,
long crtime,
long atime,
long mtime,
short modes,
int uid,
int gid, String md5Hash,
FileKnown knownState,
1481 String parentPath) {
1482 this(db, objId, db.getDataSourceObjectId(objId),
attrType, (int) attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, null, null,
OsAccount.NO_OWNER_ID,
OsAccount.NO_ACCOUNT, Collections.emptyList());
1522 @SuppressWarnings(
"deprecation")
1526 int uid,
int gid, String md5Hash,
FileKnown knownState, String parentPath, String mimeType) {
1527 this(db, objId, dataSourceObjectId,
attrType, (int) attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, null, null,
OsAccount.NO_OWNER_ID,
OsAccount.NO_ACCOUNT, Collections.emptyList());
1539 @SuppressWarnings(
"deprecation")
1566 setLocalFilePath(localPath);
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)
static Set< TSK_FS_META_FLAG_ENUM > valuesOf(short metaFlags)
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.
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()
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()
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 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)
static String epochToTime(long epoch, TimeZone tzone)
static long timeToEpoch(String time)
String getModesAsString()
int readInt(byte[] buf, long offset, long len)
Optional< String > getOwnerUid()
void save(CaseDbTransaction transaction)
UNKNOWN
File marked as unknown by hash db.
static Set< TSK_FS_META_MODE_ENUM > valuesOf(short modes)
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
TSK_FS_META_TYPE_REG
Regular file NON-NLS.
TSK_FS_META_MODE_ISGID
set group id on execution
List< TskFileRange > getFileRanges(long id)
TSK_FS_META_MODE_IXUSR
X for owner.
TskData.TSK_FS_ATTR_TYPE_ENUM getAttrType()
abstract boolean isRoot()
Optional< Long > getOsAccountObjectId()