Autopsy  4.12.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
AppSQLiteDB.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2019 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 
20 package org.sleuthkit.autopsy.coreutils;
21 
22 import java.io.Closeable;
23 import java.io.File;
24 import java.io.IOException;
25 import java.sql.Connection;
26 import java.sql.DriverManager;
27 import java.sql.ResultSet;
28 import java.sql.SQLException;
29 import java.sql.Statement;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.List;
33 import java.util.logging.Level;
39 import org.sleuthkit.datamodel.AbstractFile;
40 import org.sleuthkit.datamodel.DataSource;
41 import org.sleuthkit.datamodel.ReadContentInputStream;
42 import org.sleuthkit.datamodel.SleuthkitCase;
43 import org.sleuthkit.datamodel.TskCoreException;
44 
50 public final class AppSQLiteDB implements Closeable {
51  private final Logger logger = Logger.getLogger(AppSQLiteDB.class.getName());
52 
53  private final AbstractFile dbAbstractFile; // AbstractFile for the DB file
54 
55  private final Connection connection;
56  private final Statement statement;
57 
58 
63  private static final class AppSQLiteDBFileBundle {
64  private final AbstractFile dbAbstractFile;
65  private final File dbFileCopy;
66 
67  AppSQLiteDBFileBundle(AbstractFile dbAbstractFile, File dbFileCopy) {
68  this.dbAbstractFile = dbAbstractFile;
69  this.dbFileCopy = dbFileCopy;
70  }
71 
72  AbstractFile getAbstractFile() {
73  return dbAbstractFile;
74  }
75 
76  File getFileCopy() {
77  return dbFileCopy;
78  }
79 
80  }
81 
82  private AppSQLiteDB(AppSQLiteDBFileBundle appSQLiteDBFileBundle) throws ClassNotFoundException, SQLException {
83  this.dbAbstractFile = appSQLiteDBFileBundle.getAbstractFile();
84 
85  Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver
86  connection = DriverManager.getConnection("jdbc:sqlite:" + appSQLiteDBFileBundle.getFileCopy().getPath()); //NON-NLS
87  statement = connection.createStatement();
88  }
89 
90 
108  public static Collection<AppSQLiteDB> findAppDatabases(DataSource dataSource,
109  String dbName, boolean matchExactName, String parentPathSubstr) {
110 
111  List<AppSQLiteDB> appDbs = new ArrayList<> ();
112  try {
113  Collection<AppSQLiteDBFileBundle> dbFileBundles = findAndCopySQLiteDB( dataSource, dbName, matchExactName, parentPathSubstr, false);
114  dbFileBundles.forEach((dbFileBundle) -> {
115  try {
116  AppSQLiteDB appSQLiteDB = new AppSQLiteDB(dbFileBundle);
117  appDbs.add(appSQLiteDB);
118  } catch (ClassNotFoundException | SQLException ex) {
119  Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.SEVERE, String.format("Failed to open a DB connection for file = '%s' and path = '%s'.", dbFileBundle.dbAbstractFile.getName(), dbFileBundle.getFileCopy().getPath()), ex); //NON-NLS
120  }
121  });
122  } catch (TskCoreException ex) {
123  Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.SEVERE, String.format("Error finding App database files with name = '%s' and path = '%s'.", dbName, parentPathSubstr), ex); //NON-NLS
124  }
125 
126  return appDbs;
127  }
128 
129  public AbstractFile getDBFile() {
130  return this.dbAbstractFile;
131  }
132 
150  public AbstractFile attachDatabase(DataSource dataSource, String dbName,
151  String dbPath, String dbAlias) throws SQLException {
152  try {
153  // find and copy DB files with exact name and path.
154  Collection<AppSQLiteDBFileBundle> dbFileBundles = findAndCopySQLiteDB(dataSource, dbName, true, dbPath, true);
155  if (!dbFileBundles.isEmpty()) {
156  AppSQLiteDBFileBundle dbFileBundle = dbFileBundles.iterator().next();
157  String attachDbSql = String.format("ATTACH DATABASE '%s' AS '%s'", dbFileBundle.getFileCopy().getPath(), dbAlias); //NON-NLS
158  statement.executeUpdate(attachDbSql);
159 
160  return dbFileBundle.getAbstractFile();
161  }
162  } catch (TskCoreException ex) {
163  Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.SEVERE, String.format("Error attaching to App database files with name = '%s' and path = '%s'.", dbName, dbPath), ex); //NON-NLS
164  }
165 
166  return null;
167  }
168 
183  private static Collection<AppSQLiteDBFileBundle> findAndCopySQLiteDB(DataSource dataSource, String dbName,
184  boolean matchExactName, String dbPath, boolean matchExactPath) throws TskCoreException {
185 
186  Case openCase;
187  try {
188  openCase = Case.getCurrentCaseThrows();
189  } catch (NoCurrentCaseException ex) {
190  throw new TskCoreException("Failed to get current case.", ex);
191  }
192 
193  List<AppSQLiteDBFileBundle> dbFileBundles = new ArrayList<> ();
194  long fileId = 0;
195  String localDiskPath = "";
196 
197  SleuthkitCase skCase = openCase.getSleuthkitCase();
198  String parentPath = dbPath.replace("\\", "/");
199  parentPath = SleuthkitCase.escapeSingleQuotes(parentPath);
200 
201  String whereClause;
202  if (matchExactName) {
203  whereClause = String.format("LOWER(name) = LOWER('%s')", dbName);
204  } else {
205  whereClause = String.format("LOWER(name) LIKE LOWER('%%%s%%') AND LOWER(name) NOT LIKE LOWER('%%journal%%')", dbName );
206  }
207  if (matchExactPath) {
208  whereClause += String.format(" AND LOWER(parent_path) = LOWER('%s')", parentPath );
209  } else {
210  whereClause += String.format(" AND LOWER(parent_path) LIKE LOWER('%%%s%%')", parentPath );
211  }
212  whereClause += String.format(" AND data_source_obj_id = %s", dataSource.getId());
213 
214  List<AbstractFile> absFiles = skCase.findAllFilesWhere(whereClause);
215  for (AbstractFile absFile : absFiles) {
216  try {
217  localDiskPath = openCase.getTempDirectory()
218  + File.separator + absFile.getId() + absFile.getName();
219  File jFile = new java.io.File(localDiskPath);
220  fileId = absFile.getId();
221  ContentUtils.writeToFile(absFile, jFile);
222 
223  //Find and copy both WAL and SHM meta files
224  findAndCopySQLiteMetaFile(absFile, absFile.getName() + "-wal");
225  findAndCopySQLiteMetaFile(absFile, absFile.getName() + "-shm");
226 
227  AppSQLiteDBFileBundle dbFileBundle = new AppSQLiteDBFileBundle(absFile, jFile);
228  dbFileBundles.add(dbFileBundle);
229 
230  } catch (ReadContentInputStream.ReadContentInputStreamException ex) {
231  Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.WARNING, String.format("Error reading content from file '%s' (id=%d).", absFile.getName(), fileId), ex); //NON-NLS
232  } catch (IOException | NoCurrentCaseException | TskCoreException ex) {
233  Logger.getLogger(AppSQLiteDB.class.getName()).log(Level.SEVERE, String.format("Error creating AppSQLiteDB for file '%s' (id=%d) to copied to '%s'.", absFile.getName(), fileId, localDiskPath), ex); //NON-NLS
234  }
235  }
236 
237  return dbFileBundles;
238  }
239 
247  public void detachDatabase(String dbAlias) throws SQLException {
248  String detachDbSql = String.format("DETACH DATABASE '%s'", dbAlias);
249  statement.executeUpdate(detachDbSql); //NON-NLS
250  }
251 
252 
263  public ResultSet runQuery(String queryStr) throws SQLException {
264  ResultSet resultSet = null;
265 
266  if (null != queryStr) {
267  resultSet = statement.executeQuery(queryStr); //NON-NLS
268  }
269  return resultSet;
270  }
271 
277  @Override
278  public void close() throws IOException {
279 
280  // Close the DB connection
281  try {
282  statement.close();
283  connection.close();
284  } catch (SQLException e) {
285  logger.log(Level.SEVERE, "Error closing the database", e); //NON-NLS
286  }
287  }
288 
289 
290 
303  private static void findAndCopySQLiteMetaFile(AbstractFile sqliteFile,
304  String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException {
305 
306  Case openCase = Case.getCurrentCaseThrows();
307  SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase();
308  Services services = new Services(sleuthkitCase);
309  FileManager fileManager = services.getFileManager();
310 
311  List<AbstractFile> metaFiles = fileManager.findFiles(
312  sqliteFile.getDataSource(), metaFileName,
313  sqliteFile.getParent().getName());
314 
315  if (metaFiles != null) {
316  for (AbstractFile metaFile : metaFiles) {
317  String localDiskPath = openCase.getTempDirectory()
318  + File.separator + sqliteFile.getId() + metaFile.getName();
319  File localMetaFile = new File(localDiskPath);
320  if (!localMetaFile.exists()) {
321  ContentUtils.writeToFile(metaFile, localMetaFile);
322  }
323  }
324  }
325  }
326 }
static void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, String metaFileName)
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
AbstractFile attachDatabase(DataSource dataSource, String dbName, String dbPath, String dbAlias)
AppSQLiteDB(AppSQLiteDBFileBundle appSQLiteDBFileBundle)
static Collection< AppSQLiteDBFileBundle > findAndCopySQLiteDB(DataSource dataSource, String dbName, boolean matchExactName, String dbPath, boolean matchExactPath)
static Collection< AppSQLiteDB > findAppDatabases(DataSource dataSource, String dbName, boolean matchExactName, String parentPathSubstr)
synchronized List< AbstractFile > findFiles(String fileName)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2018 Basis Technology. Generated on: Wed Sep 18 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.