From 0b84e86887d40bdd1eb50023f0b41fb3fe6dc682 Mon Sep 17 00:00:00 2001 From: Cameron Dale Date: Thu, 17 Apr 2008 19:05:45 -0700 Subject: [PATCH] Cache returns errors if apt closes the connection and deletes the incomplete files. --- apt_p2p/CacheManager.py | 43 ++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/apt_p2p/CacheManager.py b/apt_p2p/CacheManager.py index 77e42c6..eda247d 100644 --- a/apt_p2p/CacheManager.py +++ b/apt_p2p/CacheManager.py @@ -24,6 +24,9 @@ from apt_p2p_conf import config DECOMPRESS_EXTS = ['.gz', '.bz2'] DECOMPRESS_FILES = ['release', 'sources', 'packages'] +class CacheError(Exception): + """Error occurred downloading a file to the cache.""" + class ProxyFileStream(stream.SimpleStream): """Saves a stream to a file while providing a new stream. @@ -100,9 +103,14 @@ class ProxyFileStream(stream.SimpleStream): if self.bz2file: self.bz2file.close() self.bz2file = None - - self.doneDefer.callback(self.hash) + def _error(self, err): + """Close all the output files, return the error.""" + if not self.outFile.closed: + self._done() + self.stream.close() + self.doneDefer.errback(err) + def read(self): """Read some data from the stream.""" if self.outFile.closed: @@ -111,7 +119,7 @@ class ProxyFileStream(stream.SimpleStream): # Read data from the stream, deal with the possible deferred data = self.stream.read() if isinstance(data, defer.Deferred): - data.addCallbacks(self._write, self._done) + data.addCallbacks(self._write, self._error) return data self._write(data) @@ -123,7 +131,9 @@ class ProxyFileStream(stream.SimpleStream): Also optionally decompresses it. """ if data is None: - self._done() + if not self.outFile.closed: + self._done() + self.doneDefer.callback(self.hash) return data # Write and hash the streamed data @@ -186,8 +196,13 @@ class ProxyFileStream(stream.SimpleStream): def close(self): """Clean everything up and return None to future reads.""" + log.msg('ProxyFileStream was prematurely closed after only %d/%d bytes' % (self.hash.size, self.length)) + if self.hash.size < self.length: + self._error(CacheError('Prematurely closed, all data was not written')) + elif not self.outFile.closed: + self._done() + self.doneDefer.callback(self.hash) self.length = 0 - self._done() self.stream.close() class CacheManager: @@ -369,7 +384,7 @@ class CacheManager: response.stream.doneDefer.addCallback(self._save_complete, url, destFile, response.headers.getHeader('Last-Modified'), decFile) - response.stream.doneDefer.addErrback(self.save_error, url) + response.stream.doneDefer.addErrback(self._save_error, url, destFile, decFile) # Return the modified response with the new stream return response @@ -416,8 +431,22 @@ class CacheManager: if decFile: decFile.remove() + def _save_error(self, failure, url, destFile, decFile = None): + """Remove the destination files.""" + log.msg('Error occurred downloading %s' % url) + log.err(failure) + destFile.restat(False) + if destFile.exists(): + log.msg('Removing the incomplete file: %s' % destFile.path) + destFile.remove() + if decFile: + decFile.restat(False) + if decFile.exists(): + log.msg('Removing the incomplete file: %s' % decFile.path) + decFile.remove() + def save_error(self, failure, url): - """An error has occurred in downloadign or saving the file.""" + """An error has occurred in downloading or saving the file""" log.msg('Error occurred downloading %s' % url) log.err(failure) return failure -- 2.30.2