private void addFileVersion(FileProperties fileProperties) { if (fileProperties.getChecksum() != null) { logger.log( Level.FINER, "- /File: {0} (checksum {1})", new Object[] {fileProperties.getRelativePath(), fileProperties.getChecksum()}); } else { logger.log( Level.FINER, "- /File: {0} (directory/symlink/0-byte-file)", fileProperties.getRelativePath()); } // 1. Determine if file already exists in database PartialFileHistory lastFileHistory = guessLastFileHistory(fileProperties); FileVersion lastFileVersion = (lastFileHistory != null) ? lastFileHistory.getLastVersion() : null; // 2. Create new file history/version PartialFileHistory fileHistory = createNewFileHistory(lastFileHistory); FileVersion fileVersion = createNewFileVersion(lastFileVersion, fileProperties); // 3. Compare new and last version FileProperties lastFileVersionProperties = fileVersionComparator.captureFileProperties(lastFileVersion); FileVersionComparison lastToNewFileVersionComparison = fileVersionComparator.compare(fileProperties, lastFileVersionProperties, true); boolean newVersionDiffersFromToLastVersion = !lastToNewFileVersionComparison.equals(); if (newVersionDiffersFromToLastVersion) { fileHistory.addFileVersion(fileVersion); newDatabaseVersion.addFileHistory(fileHistory); logger.log(Level.INFO, " * Added file version: " + fileVersion); logger.log(Level.INFO, " based on file version: " + lastFileVersion); } else { logger.log(Level.INFO, " * NOT ADDING file version: " + fileVersion); logger.log(Level.INFO, " b/c IDENTICAL prev.: " + lastFileVersion); } // 4. Add file content (if not a directory) if (fileProperties.getChecksum() != null && fileContent != null) { fileContent.setSize(fileProperties.getSize()); fileContent.setChecksum(fileProperties.getChecksum()); // Check if content already exists, throw gathered content away if it does! FileContent existingContent = localDatabase.getFileContent(fileProperties.getChecksum(), false); if (existingContent == null) { newDatabaseVersion.addFileContent(fileContent); } else { // Uses existing content (already in database); ref. by checksum } } }
private FileVersion createNewFileVersion( FileVersion lastFileVersion, FileProperties fileProperties) { FileVersion fileVersion = null; // Version if (lastFileVersion == null) { fileVersion = new FileVersion(); fileVersion.setVersion(1L); fileVersion.setStatus(FileStatus.NEW); } else { fileVersion = lastFileVersion.clone(); fileVersion.setVersion(lastFileVersion.getVersion() + 1); } // Simple attributes fileVersion.setPath(fileProperties.getRelativePath()); fileVersion.setLinkTarget(fileProperties.getLinkTarget()); fileVersion.setType(fileProperties.getType()); fileVersion.setSize(fileProperties.getSize()); fileVersion.setChecksum(fileProperties.getChecksum()); fileVersion.setLastModified(new Date(fileProperties.getLastModified())); fileVersion.setUpdated(new Date()); // Permissions if (EnvironmentUtil.isWindows()) { fileVersion.setDosAttributes(fileProperties.getDosAttributes()); fileVersion.setPosixPermissions(DEFAULT_POSIX_PERMISSIONS); } else if (EnvironmentUtil.isUnixLikeOperatingSystem()) { fileVersion.setPosixPermissions(fileProperties.getPosixPermissions()); fileVersion.setDosAttributes(DEFAULT_DOS_ATTRIBUTES); } // Status if (lastFileVersion != null) { if (fileVersion.getType() == FileType.FILE && FileChecksum.fileChecksumEquals( fileVersion.getChecksum(), lastFileVersion.getChecksum())) { fileVersion.setStatus(FileStatus.CHANGED); } else if (!fileVersion.getPath().equals(lastFileVersion.getPath())) { fileVersion.setStatus(FileStatus.RENAMED); } else { fileVersion.setStatus(FileStatus.CHANGED); } } return fileVersion; }
/** * Tries to guess a matching file history, first by path and then by matching checksum. * * <p>If the path matches the path of an existing file in the database, the file history from * the database is used, and a new file version is appended. If there is no file in the database * with that path, checksums are compared. * * <p>If there are more than one file with the same checksum (potential matches), the file with * the closest path is chosen. */ private PartialFileHistory guessLastFileHistoryForFile(FileProperties fileProperties) { PartialFileHistory lastFileHistory = null; // a) Try finding a file history for which the last version has the same path lastFileHistory = filePathCache.get(fileProperties.getRelativePath()); // b) If that fails, try finding files with a matching checksum if (lastFileHistory == null) { if (fileProperties.getChecksum() != null) { Collection<PartialFileHistory> fileHistoriesWithSameChecksum = fileChecksumCache.get(fileProperties.getChecksum()); if (fileHistoriesWithSameChecksum != null && fileHistoriesWithSameChecksum.size() > 0) { lastFileHistory = guessLastFileHistoryForFileWithMatchingChecksum( fileProperties, fileHistoriesWithSameChecksum); // Remove the lastFileHistory we are basing this one on from the // cache, so no other history will be fileHistoriesWithSameChecksum.remove(lastFileHistory); if (fileHistoriesWithSameChecksum.isEmpty()) { fileChecksumCache.remove(fileProperties.getChecksum()); } } } if (lastFileHistory == null) { logger.log( Level.FINER, " * No old file history found, starting new history (path: " + fileProperties.getRelativePath() + ", checksum: " + fileProperties.getChecksum() + ")"); return null; } else { logger.log( Level.FINER, " * Found old file history " + lastFileHistory.getFileHistoryId() + " (by checksum: " + fileProperties.getChecksum() + "), appending new version."); return lastFileHistory; } } else { if (fileProperties.getType() != lastFileHistory.getLastVersion().getType()) { logger.log( Level.FINER, " * No old file history found, starting new history (path: " + fileProperties.getRelativePath() + ", checksum: " + fileProperties.getChecksum() + ")"); return null; } else { logger.log( Level.FINER, " * Found old file history " + lastFileHistory.getFileHistoryId() + " (by path: " + fileProperties.getRelativePath() + "), appending new version."); return lastFileHistory; } } }