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;
59 protected final long metaAddr, ctime, crtime, atime, mtime;
61 protected final int uid, gid;
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;
73 private List<TskFileRange> ranges;
82 private boolean knownStateDirty =
false;
87 private boolean md5HashDirty =
false;
92 private boolean sha256HashDirty =
false;
98 private boolean sha1HashDirty =
false;
100 private String mimeType;
101 private boolean mimeTypeDirty =
false;
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;
109 private final String ownerUid;
112 private final Long osAccountObjId;
114 private volatile String uniquePath;
159 long dataSourceObjectId,
160 Long fileSystemObjectId,
164 long metaAddr,
int metaSeq,
168 long ctime,
long crtime,
long atime,
long mtime,
171 String md5Hash, String sha256Hash, String sha1Hash,
177 Long osAccountObjectId,
178 List<Attribute> fileAttributes) {
179 super(db, objId, name);
180 this.dataSourceObjectId = dataSourceObjectId;
181 if (fileSystemObjectId != null) {
184 if (fileSystemObjectId > 0) {
187 this.fileSystemObjectId = null;
190 this.fileSystemObjectId = null;
203 this.crtime = crtime;
213 if (knownState == null) {
219 this.mimeType = mimeType;
220 this.extension = extension == null ?
"" : extension;
222 this.ownerUid = ownerUid;
223 this.osAccountObjId = osAccountObjectId;
224 if (Objects.nonNull(fileAttributes) && !fileAttributes.isEmpty()) {
225 this.fileAttributesCache.addAll(fileAttributes);
226 loadedAttributesCacheFromDb =
true;
395 if ((mode & irusr) == irusr) {
400 if ((mode & iwusr) == iwusr) {
407 if ((mode & isuid) == isuid) {
408 if ((mode & ixusr) == ixusr) {
414 if ((mode & ixusr) == ixusr) {
422 if ((mode & irgrp) == irgrp) {
427 if ((mode & iwgrp) == iwgrp) {
434 if ((mode & isgid) == isgid) {
435 if ((mode & ixgrp) == ixgrp) {
441 if ((mode & ixgrp) == ixgrp) {
449 if ((mode & iroth) == iroth) {
454 if ((mode & iwoth) == iwoth) {
461 if ((mode & isvtx) == isvtx) {
462 if ((mode & ixoth) == ixoth) {
468 if ((mode & ixoth) == ixoth) {
476 if (result.length() != 10) {
501 this.mimeType = mimeType;
502 this.mimeTypeDirty =
true;
506 return modes.contains(mode);
519 this.md5HashDirty =
true;
541 this.sha256HashDirty =
true;
563 this.sha1HashDirty =
true;
583 synchronized (
this) {
584 if (!loadedAttributesCacheFromDb) {
586 fileAttributesCache.clear();
587 fileAttributesCache.addAll(attributes);
588 loadedAttributesCacheFromDb =
true;
590 return Collections.unmodifiableList(fileAttributesCache);
609 if (Objects.isNull(attributes) || attributes.isEmpty()) {
610 throw new TskCoreException(
"Illegal Argument passed to addAttributes: null or empty attributes passed to addAttributes");
612 boolean isLocalTransaction = Objects.isNull(caseDbTransaction);
617 for (
final Attribute attribute : attributes) {
618 attribute.setAttributeParentId(
getId());
623 if (isLocalTransaction) {
624 localTransaction.commit();
625 localTransaction = null;
628 synchronized (
this) {
629 if (loadedAttributesCacheFromDb) {
630 fileAttributesCache.addAll(attributes);
633 }
catch (SQLException ex) {
634 if (isLocalTransaction && null != localTransaction) {
636 localTransaction.rollback();
637 }
catch (TskCoreException ex2) {
638 LOGGER.log(Level.SEVERE,
"Failed to rollback transaction after exception", ex2);
641 throw new TskCoreException(
"Error adding file attributes", ex);
663 this.knownStateDirty =
true;
728 return dataSourceObjectId;
742 if (ranges == null) {
767 long rangeLength = byteRange.getByteLen();
768 if (fileOffset < rangeLength) {
769 imgOffset = byteRange.getByteStart() + fileOffset;
775 fileOffset -= rangeLength;
795 if (fileOffset < 0 || length < 0) {
799 List<TskFileRange> thisRanges =
getRanges();
800 List<TskFileRange> toRet =
new ArrayList<>();
802 long requestedEnd = fileOffset + length;
805 long bytesCounted = 0;
807 for (
int curRangeIdx = 0; curRangeIdx < thisRanges.size(); curRangeIdx++) {
809 if (bytesCounted >= requestedEnd) {
816 long curRangeEnd = bytesCounted + curRangeLen;
821 if (fileOffset < curRangeEnd) {
823 long rangeOffset = Math.max(0, fileOffset - bytesCounted);
826 long newRangeStart = curRange.
getByteStart() + rangeOffset;
829 long rangeOvershoot = Math.max(0, curRangeEnd - requestedEnd);
831 long newRangeLen = curRangeLen - rangeOffset - rangeOvershoot;
832 toRet.add(
new TskFileRange(newRangeStart, newRangeLen, toRet.size()));
835 bytesCounted = curRangeEnd;
883 public abstract boolean isRoot();
896 String[] pathSegments = uniquePath.split(
"/");
900 if (pathSegments[0].startsWith(
"img_")) {
903 if (pathSegments[1].startsWith(
"vol_")) {
909 StringBuilder strbuf =
new StringBuilder();
910 for (; index < pathSegments.length; ++index) {
911 if (!pathSegments[index].isEmpty()) {
912 strbuf.append(
"/").append(pathSegments[index]);
916 return strbuf.toString();
930 List<AbstractFile> files =
new ArrayList<AbstractFile>();
931 for (
Content child : children) {
933 AbstractFile afChild = (AbstractFile) child;
963 return dirType.toString();
972 return dirFlag == flag;
1011 return metaFlags.contains(metaFlag);
1020 metaFlags.add(metaFlag);
1028 void removeMetaFlag(TSK_FS_META_FLAG_ENUM metaFlag) {
1029 metaFlags.remove(metaFlag);
1037 short getMetaFlagsAsInt() {
1038 return TSK_FS_META_FLAG_ENUM.toInt(metaFlags);
1048 return readInt(buf, offset, len);
1080 if (!localPathSet) {
1082 BUNDLE.getString(
"AbstractFile.readLocal.exception.msg1.text"));
1098 if (localFileHandle == null) {
1099 synchronized (
this) {
1100 if (localFileHandle == null) {
1102 localFileHandle =
new RandomAccessFile(localFile,
"r");
1103 }
catch (FileNotFoundException ex) {
1104 final String msg = MessageFormat.format(BUNDLE.getString(
1105 "AbstractFile.readLocal.exception.msg4.text"),
1107 LOGGER.log(Level.SEVERE, msg, ex);
1119 long encodedOffset = offset + EncodedFileUtil.getHeaderLength();
1122 long curOffset = localFileHandle.getFilePointer();
1123 if (curOffset != encodedOffset) {
1124 localFileHandle.seek(encodedOffset);
1126 bytesRead = localFileHandle.read(buf, 0, (
int) len);
1127 for (
int i = 0; i < bytesRead; i++) {
1128 buf[i] = EncodedFileUtil.decodeByte(buf[i], encodingType);
1133 long curOffset = localFileHandle.getFilePointer();
1134 if (curOffset != offset) {
1135 localFileHandle.seek(offset);
1138 return localFileHandle.read(buf, 0, (
int) len);
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);
1155 void setLocalFilePath(String localPath) {
1157 if (localPath == null || localPath.equals(
"")) {
1158 this.localPath =
"";
1159 localAbsPath = null;
1160 localPathSet =
false;
1165 this.localPath = localPath;
1166 if (
this instanceof DerivedFile) {
1172 if (localPath.startsWith(
"/") || localPath.startsWith(
"\\")
1173 || localPath.matches(
"[A-Za-z]:[/\\\\].*")) {
1174 this.localAbsPath = localPath;
1179 this.localPathSet =
true;
1198 return localAbsPath;
1207 this.encodingType = encodingType;
1217 if (!localPathSet) {
1222 return localFile.
exists();
1224 LOGGER.log(Level.SEVERE, ex.getMessage());
1238 if (!localPathSet) {
1245 LOGGER.log(Level.SEVERE, ex.getMessage());
1258 if (!localPathSet) {
1259 throw new TskCoreException(
1260 BUNDLE.getString(
"AbstractFile.readLocal.exception.msg1.text"));
1264 if (localFile != null) {
1268 synchronized (
this) {
1269 if (localFile == null) {
1270 localFile =
new java.io.File(localAbsPath);
1279 if (localFileHandle != null) {
1280 synchronized (
this) {
1281 if (localFileHandle != null) {
1283 localFileHandle.close();
1284 }
catch (IOException ex) {
1285 LOGGER.log(Level.SEVERE,
"Could not close file handle for file: " +
getParentPath() +
getName(), ex);
1287 localFileHandle = null;
1294 @SuppressWarnings(
"deprecation")
1306 return super.toString(preserveState) +
"AbstractFile [\t"
1308 +
"\tctime " + ctime
1309 +
"\tcrtime " + crtime
1310 +
"\t" +
"mtime " + mtime +
"\t" +
"atime " + atime
1311 +
"\t" +
"attrId " + attrId
1313 +
"\t" +
"dirFlag " + dirFlag +
"\t" +
"dirType " + dirType
1314 +
"\t" +
"uid " + uid
1315 +
"\t" +
"gid " + gid
1316 +
"\t" +
"metaAddr " + metaAddr +
"\t" +
"metaSeq " + metaSeq +
"\t" +
"metaFlags " + metaFlags
1317 +
"\t" +
"metaType " + metaType +
"\t" +
"modes " +
modes
1318 +
"\t" +
"parentPath " + parentPath +
"\t" +
"size " + size
1319 +
"\t" +
"knownState " +
knownState +
"\t" +
"md5Hash " + md5Hash +
"\t" +
"sha256Hash " + sha256Hash +
"\t" +
"sha1Hash " + sha1Hash
1320 +
"\t" +
"localPathSet " + localPathSet +
"\t" +
"localPath " + localPath
1321 +
"\t" +
"localAbsPath " + localAbsPath +
"\t" +
"localFile " + localFile
1344 if (this.mimeType == null) {
1347 if (mimeTypes.contains(
this.mimeType)) {
1360 public void save() throws TskCoreException {
1366 }
catch (TskCoreException ex) {
1367 if (transaction != null) {
1385 if (!(md5HashDirty || sha256HashDirty || sha1HashDirty || mimeTypeDirty || knownStateDirty)) {
1389 String updateSql =
"";
1390 if (mimeTypeDirty) {
1391 updateSql =
"mime_type = '" + this.
getMIMEType() +
"'";
1394 if (!updateSql.isEmpty()) {
1397 updateSql +=
"md5 = '" + this.
getMd5Hash() +
"'";
1399 if (sha256HashDirty) {
1400 if (!updateSql.isEmpty()) {
1405 if (sha1HashDirty) {
1406 if (!updateSql.isEmpty()) {
1409 updateSql +=
"sha1 = '" + this.
getSha1Hash() +
"'";
1411 if (knownStateDirty) {
1412 if (!updateSql.isEmpty()) {
1415 updateSql +=
"known = '" + this.
getKnown().getFileKnownValue() +
"'";
1417 updateSql =
"UPDATE tsk_files SET " + updateSql +
" WHERE obj_id = " + this.
getId();
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);
1441 return Optional.ofNullable(ownerUid);
1450 return Optional.ofNullable(osAccountObjId);
1459 parentFileSystem = parent;
1468 return Optional.ofNullable(fileSystemObjectId);
1477 return fileSystemObjectId != null;
1492 if (fileSystemObjectId == null) {
1493 throw new TskCoreException(
"File with ID: " + this.
getId() +
" does not belong to a file system");
1495 if (parentFileSystem == null) {
1496 synchronized (
this) {
1497 if (parentFileSystem == null) {
1502 return parentFileSystem;
1516 if (uniquePath == null) {
1522 StringBuilder sb =
new StringBuilder();
1524 if (! parentPath.isEmpty()) {
1525 sb.append(parentPath);
1531 uniquePath = sb.toString();
1533 if ((
this instanceof
LayoutFile) && (parentPath.equals(
"/"))) {
1537 uniquePath = super.getUniquePath();
1543 uniquePath = super.getUniquePath();
1549 String dataSourceName =
"";
1551 if (dataSource != null) {
1554 if (! parentPath.isEmpty()) {
1555 uniquePath = dataSourceName + parentPath +
getName();
1558 uniquePath = dataSourceName +
"/" +
getName();
1567 @SuppressWarnings(
"deprecation")
1600 @SuppressWarnings(
"deprecation")
1627 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.
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()
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)
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.
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
static final long UNKNOWN_ID
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()
void setSha1Hash(String sha1Hash)
FileSystem getFileSystem()
abstract boolean isRoot()
Optional< Long > getOsAccountObjectId()