Skip to content

Commit e5a8d44

Browse files
committed
Fixed download-size issues. Also no longer truncating files.
Fixes dsoprea#111. Fixes dsoprea#116.
1 parent 73fbefd commit e5a8d44

File tree

3 files changed

+65
-35
lines changed

3 files changed

+65
-35
lines changed

gdrivefs/gdfs/opened_file.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ def __load_base_from_remote(self):
301301
_logger.exception("There was an export-format error.")
302302
raise fuse.FuseOSError(ENOENT)
303303

304-
self.__fh = open(self.__temp_filepath, 'w+')
304+
self.__fh = open(self.__temp_filepath, 'r+')
305305

306306
self.__is_dirty = False
307307
self.__is_loaded = True
@@ -370,7 +370,7 @@ def flush(self):
370370
@dec_hint(['offset', 'length'], prefix='OF')
371371
def read(self, offset, length):
372372

373-
_logger.debug("Checking write-cache file (flush).")
373+
_logger.debug("Reading (%d) bytes at offset (%d).", length, offset)
374374

375375
# We don't care if the cache file is dirty (not on this system, at
376376
# least).
@@ -380,8 +380,14 @@ def read(self, offset, length):
380380
self.__fh.seek(offset)
381381
data = self.__fh.read(length)
382382

383+
len_ = len(data)
384+
383385
_logger.debug("(%d) bytes retrieved from slice (%d):(%d)/(%d).",
384-
len(data), offset, length, st.st_size)
386+
len_, offset, length, st.st_size)
387+
388+
if len_ != length:
389+
_logger.warning("Read request is only returning (%d) bytes when "
390+
"(%d) bytes were requested.", len_, length)
385391

386392
return data
387393

gdrivefs/gdtool/chunked_download.py

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def next_chunk(self, num_retries=0):
7070

7171
for retry_num in xrange(num_retries + 1):
7272
_logger.debug("Attempting to read chunk. ATTEMPT=(%d)/(%d)",
73-
retry_num, num_retries)
73+
retry_num + 1, num_retries + 1)
7474

7575
if retry_num > 0:
7676
self._sleep(self._rand() * 2**retry_num)
@@ -79,36 +79,57 @@ def next_chunk(self, num_retries=0):
7979
retry_num, self._uri, resp.status)
8080

8181
resp, content = self._http.request(self._uri, headers=headers)
82-
_logger.debug("Chunk status: (%d)", resp.status)
8382
if resp.status < 500:
8483
break
8584

86-
if resp.status in [200, 206]:
87-
if 'content-location' in resp and resp['content-location'] != self._uri:
88-
self._uri = resp['content-location']
85+
_logger.debug("Received chunk of size (%d).", len(content))
8986

90-
self._progress += len(content)
87+
if resp.status in [200, 206]:
88+
try:
89+
if resp['content-location'] != self._uri:
90+
self._uri = resp['content-location']
91+
except KeyError:
92+
pass
93+
94+
received_size_b = len(content)
95+
self._progress += received_size_b
9196
self._fd.write(content)
9297

93-
# This method doesn't seem documented, but we've seen cases where
94-
# this is available, but "content-range" isn't.
95-
if 'content-length' in resp:
96-
self._total_size = int(resp['content-length'])
97-
98-
_logger.debug("Received download size (content-length): "
99-
"(%d)", self._total_size)
100-
101-
# This might be legacy (or at least not provided for zero-length
102-
# files).
103-
elif 'content-range' in resp and self._total_size is None:
104-
content_range = resp['content-range']
105-
length = content_range.rsplit('/', 1)[1]
106-
length = int(length)
107-
108-
self._total_size = length
98+
# This seems to be the most correct method to get the filesize, but
99+
# we've seen it not exist.
100+
if 'content-range' in resp:
101+
if self._total_size is None:
102+
content_range = resp['content-range']
103+
length = content_range.rsplit('/', 1)[1]
104+
length = int(length)
105+
106+
self._total_size = length
107+
108+
_logger.debug("Received download size (content-range): "
109+
"(%d)", self._total_size)
110+
111+
# There's a chance that "content-range" will be omitted for zero-
112+
# length files (or maybe files that are complete within the first
113+
# chunk).
114+
115+
else:
116+
# TODO(dustin): Is this a valid assumption, or should it be an error?
117+
_logger.warning("No 'content-range' found in response. "
118+
"Assuming that we've received all data.")
119+
120+
self._total_size = received_size_b
121+
122+
# TODO(dustin): We were using this for a while, but it appears to be no larger
123+
# then a single chunk.
124+
#
125+
# # This method doesn't seem documented, but we've seen cases where
126+
# # this is available, but "content-range" isn't.
127+
# if 'content-length' in resp:
128+
# self._total_size = int(resp['content-length'])
129+
#
130+
# _logger.debug("Received download size (content-length): "
131+
# "(%d)", self._total_size)
109132

110-
_logger.debug("Received download size (content-range): "
111-
"(%d)", self._total_size)
112133

113134
assert self._total_size is not None, \
114135
"File-size was not provided."

gdrivefs/gdtool/drive.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,6 @@ def list_changes(self, start_change_id=None, page_token=None):
204204
back. Change-IDs are integers, but are not necessarily sequential.
205205
"""
206206

207-
_logger.debug("Listing changes starting at ID [%s] with page_token "
208-
"[%s].", start_change_id, page_token)
209-
210207
client = self.__auth.get_client()
211208

212209
response = client.changes().list(
@@ -216,6 +213,10 @@ def list_changes(self, start_change_id=None, page_token=None):
216213
self.__assert_response_kind(response, 'drive#changeList')
217214

218215
items = response[u'items']
216+
217+
if items:
218+
_logger.debug("We received (%d) changes to apply.", len(items))
219+
219220
largest_change_id = int(response[u'largestChangeId'])
220221
next_page_token = response.get(u'nextPageToken')
221222

@@ -408,8 +409,8 @@ def download_to_local(self, output_file_path, normalized_entry, mime_type,
408409
the data has changed since any prior attempts.
409410
"""
410411

411-
_logger.info("Downloading entry with ID [%s] and mime-type [%s].",
412-
normalized_entry.id, mime_type)
412+
_logger.info("Downloading entry with ID [%s] and mime-type [%s] to "
413+
"[%s].", normalized_entry.id, mime_type, output_file_path)
413414

414415
if mime_type != normalized_entry.mime_type and \
415416
mime_type not in normalized_entry.download_links:
@@ -464,7 +465,6 @@ def download_to_local(self, output_file_path, normalized_entry, mime_type,
464465

465466
while 1:
466467
status, done, total_size = downloader.next_chunk()
467-
468468
assert status.total_size is not None, \
469469
"total_size is None"
470470

@@ -492,6 +492,8 @@ def download_to_local(self, output_file_path, normalized_entry, mime_type,
492492
if done is True:
493493
break
494494

495+
_logger.debug("Download complete. Offset is: (%d)", f.tell())
496+
495497
utime(output_file_path, (time.time(), gd_mtime_epoch))
496498

497499
return (total_size, True)
@@ -548,9 +550,10 @@ def __insert_entry(self, is_file, filename, parents, mime_type,
548550
accessed_datetime = now_phrase
549551

550552
_logger.info("Creating entry with filename [%s] under parent(s) "
551-
"[%s] with mime-type [%s]. MTIME=[%s] ATIME=[%s]",
553+
"[%s] with mime-type [%s]. MTIME=[%s] ATIME=[%s] "
554+
"DATA_FILEPATH=[%s]",
552555
filename, ', '.join(parents), mime_type,
553-
modified_datetime, accessed_datetime)
556+
modified_datetime, accessed_datetime, data_filepath)
554557

555558
client = self.__auth.get_client()
556559

0 commit comments

Comments
 (0)