100 lines
3.3 KiB
Diff
100 lines
3.3 KiB
Diff
|
|
From 64b53f59bccb8ec3251826c06d74adbc7b3cad36 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Luo Yifan <luoyifan_yewu@cmss.chinamobile.com>
|
||
|
|
Date: Mon, 16 Dec 2024 10:27:44 +0800
|
||
|
|
Subject: [PATCH] vvfat: Fix vvfat_write() for writes before the root directory
|
||
|
|
|
||
|
|
cherry picked from commit b9b8860d24676ec59c878d5206ea6bcfc87af798
|
||
|
|
|
||
|
|
The calculation in sector2cluster() is done relative to the offset of
|
||
|
|
the root directory. Any writes to blocks before the start of the root
|
||
|
|
directory (in particular, writes to the FAT) result in negative values,
|
||
|
|
which are not handled correctly in vvfat_write().
|
||
|
|
|
||
|
|
This changes sector2cluster() to return a signed value, and makes sure
|
||
|
|
that vvfat_write() doesn't try to find mappings for negative cluster
|
||
|
|
number. It clarifies the code in vvfat_write() to make it more obvious
|
||
|
|
that the cluster numbers can be negative.
|
||
|
|
|
||
|
|
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||
|
|
Message-Id: <20211209152231.23756-1-kwolf@redhat.com>
|
||
|
|
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
||
|
|
Signed-off-by: Luo Yifan <luoyifan_yewu@cmss.chinamobile.com>
|
||
|
|
---
|
||
|
|
block/vvfat.c | 30 ++++++++++++++++++++++--------
|
||
|
|
1 file changed, 22 insertions(+), 8 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/block/vvfat.c b/block/vvfat.c
|
||
|
|
index 3691c4774e..935a10bdd3 100644
|
||
|
|
--- a/block/vvfat.c
|
||
|
|
+++ b/block/vvfat.c
|
||
|
|
@@ -882,7 +882,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
-static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
|
||
|
|
+static inline int32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
|
||
|
|
{
|
||
|
|
return (sector_num - s->offset_to_root_dir) / s->sectors_per_cluster;
|
||
|
|
}
|
||
|
|
@@ -2983,6 +2983,7 @@ static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
|
||
|
|
{
|
||
|
|
BDRVVVFATState *s = bs->opaque;
|
||
|
|
int i, ret;
|
||
|
|
+ int first_cluster, last_cluster;
|
||
|
|
|
||
|
|
DLOG(checkpoint());
|
||
|
|
|
||
|
|
@@ -3001,9 +3002,20 @@ DLOG(checkpoint());
|
||
|
|
if (sector_num < s->offset_to_fat)
|
||
|
|
return -1;
|
||
|
|
|
||
|
|
- for (i = sector2cluster(s, sector_num);
|
||
|
|
- i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
|
||
|
|
- mapping_t* mapping = find_mapping_for_cluster(s, i);
|
||
|
|
+ /*
|
||
|
|
+ * Values will be negative for writes to the FAT, which is located before
|
||
|
|
+ * the root directory.
|
||
|
|
+ */
|
||
|
|
+ first_cluster = sector2cluster(s, sector_num);
|
||
|
|
+ last_cluster = sector2cluster(s, sector_num + nb_sectors - 1);
|
||
|
|
+
|
||
|
|
+ for (i = first_cluster; i <= last_cluster;) {
|
||
|
|
+ mapping_t *mapping = NULL;
|
||
|
|
+
|
||
|
|
+ if (i >= 0) {
|
||
|
|
+ mapping = find_mapping_for_cluster(s, i);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
if (mapping) {
|
||
|
|
if (mapping->read_only) {
|
||
|
|
fprintf(stderr, "Tried to write to write-protected file %s\n",
|
||
|
|
@@ -3043,8 +3055,9 @@ DLOG(checkpoint());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
i = mapping->end;
|
||
|
|
- } else
|
||
|
|
+ } else {
|
||
|
|
i++;
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
@@ -3058,10 +3071,11 @@ DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sec
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
- for (i = sector2cluster(s, sector_num);
|
||
|
|
- i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
|
||
|
|
- if (i >= 0)
|
||
|
|
+ for (i = first_cluster; i <= last_cluster; i++) {
|
||
|
|
+ if (i >= 0) {
|
||
|
|
s->used_clusters[i] |= USED_ALLOCATED;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
|
||
|
|
DLOG(checkpoint());
|
||
|
|
/* TODO: add timeout */
|
||
|
|
--
|
||
|
|
2.41.0.windows.1
|
||
|
|
|