fat16copy: Fix allocation logic when extending directories.
When extending a directory, empty directory entries were left behind
signaling the end of a directory.
Bug: 31570546
Test: make dist; mdir shows all the files.
(cherry picked from commit d4516300b010c8155861e310dac871e8c10d3382)
Change-Id: Ie3d82cfaad51be73911293a54d18746e8adf62a2
diff --git a/tools/fat16copy.py b/tools/fat16copy.py
index f49c4fe..af8bd83 100755
--- a/tools/fat16copy.py
+++ b/tools/fat16copy.py
@@ -222,11 +222,8 @@
data.seek(0, os.SEEK_END)
size = data.tell()
- chunk = 0
-
- if size > 0:
- chunk = self.backing.fs.allocate(size)
-
+ # Empty files shouldn't have any clusters assigned.
+ chunk = self.backing.fs.allocate(size) if size > 0 else 0
(shortname, ext) = self.make_short_name(name)
self.add_dentry(0, shortname, ext, name, chunk, size)
@@ -393,28 +390,23 @@
record_count = len(longname_record_data) + 1
found_count = 0
-
- while True:
+ while found_count < record_count:
record = f.read(32)
if record is None or len(record) != 32:
- break
+ # We reached the EOF, so we need to extend the file with a new cluster.
+ f.write("\0" * self.fs.bytes_per_cluster)
+ f.seek(-self.fs.bytes_per_cluster, os.SEEK_CUR)
+ record = f.read(32)
marker = struct.unpack("B", record[0])[0]
if marker == DEL_MARKER or marker == 0:
found_count += 1
-
- if found_count == record_count:
- break
else:
found_count = 0
- if found_count != record_count:
- f.write("\0" * self.fs.bytes_per_cluster)
- f.seek(-self.fs.bytes_per_cluster, os.SEEK_CUR)
- else:
- f.seek(-(record_count * 32), os.SEEK_CUR)
+ f.seek(-(record_count * 32), os.SEEK_CUR)
f.write(entry)
class root_dentry_file(fake_file):
@@ -637,7 +629,6 @@
Allocate a new cluster chain big enough to hold at least the given amount
of bytes.
"""
-
assert amount > 0, "Must allocate a non-zero amount."
f = self.f
@@ -702,39 +693,17 @@
Given a cluster which is the *last* cluster in a chain, extend it to hold
at least `amount` more bytes.
"""
- return_cluster = None
+ if amount == 0:
+ return
f = self.f
-
- position = FAT_TABLE_START + cluster * 2
- f.seek(position)
-
+ entry_offset = FAT_TABLE_START + cluster * 2
+ f.seek(entry_offset)
assert read_le_short(f) == 0xFFFF, "Extending from middle of chain"
- rewind_short(f)
- while position + 2 < FAT_TABLE_START + self.fat_size and amount > 0:
- skip_short(f)
- got = read_le_short(f)
- rewind_short(f)
- rewind_short(f)
-
- if got != 0:
- break
-
- cluster += 1
- return_cluster = return_cluster or cluster
- position += 2
- self.write_cluster_entry(cluster)
- amount -= self.bytes_per_cluster
-
- if amount <= 0:
- self.write_cluster_entry(0xFFFF)
- return return_cluster
-
- new_chunk = self.allocate(amount)
- f.seek(FAT_TABLE_START + cluster * 2)
- self.write_cluster_entry(new_chunk)
-
- return return_cluster or new_chunk
+ return_cluster = self.allocate(amount)
+ f.seek(entry_offset)
+ self.write_cluster_entry(return_cluster)
+ return return_cluster
def write_file(self, head_cluster, start_byte, data):
"""
@@ -745,35 +714,31 @@
data: The data to write.
"""
f = self.f
+ last_offset = start_byte + len(data)
+ current_offset = 0
+ current_cluster = head_cluster
- while True:
- if start_byte < self.bytes_per_cluster:
- to_write = data[:self.bytes_per_cluster - start_byte]
- data = data[self.bytes_per_cluster - start_byte:]
+ while current_offset < last_offset:
+ # Write everything that falls in the cluster starting at current_offset.
+ data_begin = max(0, current_offset - start_byte)
+ data_end = min(len(data),
+ current_offset + self.bytes_per_cluster - start_byte)
+ if data_end > data_begin:
+ cluster_file_offset = (self.data_start() + self.root_entries * 32 +
+ (current_cluster - 2) * self.bytes_per_cluster)
+ f.seek(cluster_file_offset + max(0, start_byte - current_offset))
+ f.write(data[data_begin:data_end])
- cluster_bytes_from_root = (head_cluster - 2) * \
- self.bytes_per_cluster
- bytes_from_root = cluster_bytes_from_root + start_byte
- bytes_from_data_start = bytes_from_root + self.root_entries * 32
+ # Advance to the next cluster in the chain or get a new cluster if needed.
+ current_offset += self.bytes_per_cluster
+ if last_offset > current_offset:
+ f.seek(FAT_TABLE_START + current_cluster * 2)
+ next_cluster = read_le_short(f)
+ if next_cluster > MAX_CLUSTER_ID:
+ next_cluster = self.extend_cluster(current_cluster, len(data))
+ current_cluster = next_cluster
+ assert current_cluster > 0, "Cannot write free cluster"
- f.seek(self.data_start() + bytes_from_data_start)
- f.write(to_write)
-
- if len(data) == 0:
- return
-
- start_byte -= self.bytes_per_cluster
-
- if start_byte < 0:
- start_byte = 0
-
- f.seek(FAT_TABLE_START + head_cluster * 2)
- next_cluster = read_le_short(f)
- if next_cluster > MAX_CLUSTER_ID:
- head_cluster = self.extend_cluster(head_cluster, len(data))
- else:
- head_cluster = next_cluster
- assert head_cluster > 0, "Cannot write free cluster"
def add_item(directory, item):
"""