use of org.syncany.database.MultiChunkEntry.MultiChunkId in project syncany by syncany.
the class MultiChunkSqlDao method createMultiChunkEntriesWithChunks.
private Map<MultiChunkId, MultiChunkEntry> createMultiChunkEntriesWithChunks(ResultSet resultSet) throws SQLException {
Map<MultiChunkId, MultiChunkEntry> multiChunkEntries = new HashMap<MultiChunkId, MultiChunkEntry>();
MultiChunkId currentMultiChunkId = null;
while (resultSet.next()) {
MultiChunkId multiChunkId = MultiChunkId.parseMultiChunkId(resultSet.getString("multichunk_id"));
long multiChunkSize = resultSet.getLong("size");
MultiChunkEntry multiChunkEntry = null;
if (currentMultiChunkId != null && currentMultiChunkId.equals(multiChunkId)) {
multiChunkEntry = multiChunkEntries.get(multiChunkId);
} else {
multiChunkEntry = new MultiChunkEntry(multiChunkId, multiChunkSize);
}
multiChunkEntry.addChunk(ChunkChecksum.parseChunkChecksum(resultSet.getString("chunk_checksum")));
multiChunkEntries.put(multiChunkId, multiChunkEntry);
currentMultiChunkId = multiChunkId;
}
return multiChunkEntries;
}
use of org.syncany.database.MultiChunkEntry.MultiChunkId in project syncany by syncany.
the class Downloader method downloadAndDecryptMultiChunks.
/**
* Downloads the given multichunks from the remote storage and decrypts them
* to the local cache folder.
*/
public void downloadAndDecryptMultiChunks(Set<MultiChunkId> unknownMultiChunkIds) throws StorageException, IOException {
logger.log(Level.INFO, "Downloading and extracting multichunks ...");
int multiChunkNumber = 0;
for (MultiChunkId multiChunkId : unknownMultiChunkIds) {
File localEncryptedMultiChunkFile = config.getCache().getEncryptedMultiChunkFile(multiChunkId);
File localDecryptedMultiChunkFile = config.getCache().getDecryptedMultiChunkFile(multiChunkId);
MultichunkRemoteFile remoteMultiChunkFile = new MultichunkRemoteFile(multiChunkId);
multiChunkNumber++;
if (localDecryptedMultiChunkFile.exists()) {
logger.log(Level.INFO, " + Decrypted multichunk exists locally " + multiChunkId + ". No need to download it!");
} else {
eventBus.post(new DownDownloadFileSyncExternalEvent(config.getLocalDir().getAbsolutePath(), "multichunk", multiChunkNumber, unknownMultiChunkIds.size()));
logger.log(Level.INFO, " + Downloading multichunk " + multiChunkId + " ...");
transferManager.download(remoteMultiChunkFile, localEncryptedMultiChunkFile);
try {
logger.log(Level.INFO, " + Decrypting multichunk " + multiChunkId + " ...");
InputStream multiChunkInputStream = config.getTransformer().createInputStream(new FileInputStream(localEncryptedMultiChunkFile));
OutputStream decryptedMultiChunkOutputStream = new FileOutputStream(localDecryptedMultiChunkFile);
IOUtils.copy(multiChunkInputStream, decryptedMultiChunkOutputStream);
decryptedMultiChunkOutputStream.close();
multiChunkInputStream.close();
} catch (IOException e) {
// Security: Deleting the multichunk if the decryption/extraction failed is important!
// If it is not deleted, the partially decrypted multichunk will reside in the
// local cache and the next 'down' will try to use it. If this is the only
// multichunk that has been tampered with, other changes might be applied to the
// file system! See https://github.com/syncany/syncany/issues/59#issuecomment-55154793
logger.log(Level.FINE, " -> FAILED: Decryption/extraction of multichunk failed, deleting " + multiChunkId + " ...");
localDecryptedMultiChunkFile.delete();
throw new IOException("Decryption/extraction of multichunk " + multiChunkId + " failed. The multichunk might have been tampered with!", e);
} finally {
logger.log(Level.FINE, " + Locally deleting multichunk " + multiChunkId + " ...");
localEncryptedMultiChunkFile.delete();
}
}
}
transferManager.disconnect();
}
use of org.syncany.database.MultiChunkEntry.MultiChunkId in project syncany by syncany.
the class UpOperation method addMultiChunksToTransaction.
/**
* This methods adds the multichunks that are not yet present in the remote repo to the {@link RemoteTransaction} for
* uploading. Multichunks are not uploaded if they are dirty.
*
* @param multiChunkEntries Collection of multiChunkEntries that are included in the new {@link DatabaseVersion}
*/
private void addMultiChunksToTransaction(RemoteTransaction remoteTransaction, Collection<MultiChunkEntry> multiChunksEntries) throws InterruptedException, StorageException {
List<MultiChunkId> dirtyMultiChunkIds = localDatabase.getDirtyMultiChunkIds();
for (MultiChunkEntry multiChunkEntry : multiChunksEntries) {
if (dirtyMultiChunkIds.contains(multiChunkEntry.getId())) {
logger.log(Level.INFO, "- Ignoring multichunk (from dirty database, already uploaded), " + multiChunkEntry.getId() + " ...");
} else {
File localMultiChunkFile = config.getCache().getEncryptedMultiChunkFile(multiChunkEntry.getId());
MultichunkRemoteFile remoteMultiChunkFile = new MultichunkRemoteFile(multiChunkEntry.getId());
logger.log(Level.INFO, "- Uploading multichunk {0} from {1} to {2} ...", new Object[] { multiChunkEntry.getId(), localMultiChunkFile, remoteMultiChunkFile });
remoteTransaction.upload(localMultiChunkFile, remoteMultiChunkFile);
}
}
}
use of org.syncany.database.MultiChunkEntry.MultiChunkId in project syncany by syncany.
the class ApplyChangesOperation method determineMultiChunksToDownload.
/**
* Finds the multichunks that need to be downloaded for the given file version -- using the local
* database and given winners database. Returns a set of multichunk identifiers.
*/
private Collection<MultiChunkId> determineMultiChunksToDownload(FileVersion fileVersion, MemoryDatabase winnersDatabase) {
Set<MultiChunkId> multiChunksToDownload = new HashSet<MultiChunkId>();
// First: Check if we know this file locally!
List<MultiChunkId> multiChunkIds = localDatabase.getMultiChunkIds(fileVersion.getChecksum());
if (multiChunkIds.size() > 0) {
multiChunksToDownload.addAll(multiChunkIds);
} else {
// Second: We don't know it locally; must be from the winners database
FileContent winningFileContent = winnersDatabase.getContent(fileVersion.getChecksum());
boolean winningFileHasContent = winningFileContent != null;
if (winningFileHasContent) {
// File can be empty!
List<ChunkChecksum> fileChunks = winningFileContent.getChunks();
// TODO [medium] Instead of just looking for multichunks to download here, we should look for chunks in local files as well
// and return the chunk positions in the local files ChunkPosition (chunk123 at file12, offset 200, size 250)
Map<ChunkChecksum, MultiChunkId> checksumsWithMultiChunkIds = localDatabase.getMultiChunkIdsByChecksums(fileChunks);
for (ChunkChecksum chunkChecksum : fileChunks) {
MultiChunkId multiChunkIdForChunk = checksumsWithMultiChunkIds.get(chunkChecksum);
if (multiChunkIdForChunk == null) {
multiChunkIdForChunk = winnersDatabase.getMultiChunkIdForChunk(chunkChecksum);
if (multiChunkIdForChunk == null) {
throw new RuntimeException("Cannot find multichunk for chunk " + chunkChecksum);
}
}
if (!multiChunksToDownload.contains(multiChunkIdForChunk)) {
logger.log(Level.INFO, " + Adding multichunk " + multiChunkIdForChunk + " to download list ...");
multiChunksToDownload.add(multiChunkIdForChunk);
}
}
}
}
return multiChunksToDownload;
}
use of org.syncany.database.MultiChunkEntry.MultiChunkId in project syncany by syncany.
the class GetFileFolderRequestHandler method handleRequest.
@Override
public Response handleRequest(FolderRequest request) {
GetFileFolderRequest concreteRequest = (GetFileFolderRequest) request;
try {
FileHistoryId fileHistoryId = FileHistoryId.parseFileId(concreteRequest.getFileHistoryId());
long version = concreteRequest.getVersion();
FileVersion fileVersion = localDatabase.getFileVersion(fileHistoryId, version);
FileContent fileContent = localDatabase.getFileContent(fileVersion.getChecksum(), true);
Map<ChunkChecksum, MultiChunkId> multiChunks = localDatabase.getMultiChunkIdsByChecksums(fileContent.getChunks());
TransferManager transferManager = config.getTransferPlugin().createTransferManager(config.getConnection(), config);
Downloader downloader = new Downloader(config, transferManager);
Assembler assembler = new Assembler(config, localDatabase);
downloader.downloadAndDecryptMultiChunks(new HashSet<MultiChunkId>(multiChunks.values()));
File tempFile = assembler.assembleToCache(fileVersion);
String tempFileToken = StringUtil.toHex(ObjectId.secureRandomBytes(40));
GetFileFolderResponse fileResponse = new GetFileFolderResponse(concreteRequest.getId(), concreteRequest.getRoot(), tempFileToken);
GetFileFolderResponseInternal fileResponseInternal = new GetFileFolderResponseInternal(fileResponse, tempFile);
eventBus.post(fileResponseInternal);
return null;
} catch (Exception e) {
logger.log(Level.WARNING, "Cannot reassemble file.", e);
return new BadRequestResponse(concreteRequest.getId(), "Cannot reassemble file.");
}
}
Aggregations