fs-util: make sure conservative_renameat() properly detects identity of longer files

The old code got confused with files with a size >16K. Let's fix that.

Noticed by @benjarobin

Replaces: #18442
This commit is contained in:
Lennart Poettering
2021-02-04 18:25:25 +01:00
parent 84c46fb03c
commit eff57d1c2f
+21 -7
View File
@@ -1656,23 +1656,37 @@ int conservative_renameat(
goto do_rename;
for (;;) {
char buf1[16*1024];
char buf2[sizeof(buf1) + 1];
uint8_t buf1[16*1024];
uint8_t buf2[sizeof(buf1)];
ssize_t l1, l2;
l1 = read(old_fd, buf1, sizeof(buf1));
if (l1 < 0)
goto do_rename;
l2 = read(new_fd, buf2, l1 + 1);
if (l1 != l2)
goto do_rename;
if (l1 == sizeof(buf1))
/* Read the full block, hence read a full block in the other file too */
if (l1 == 0) /* EOF on both! And everything's the same so far, yay! */
break;
l2 = read(new_fd, buf2, l1);
else {
assert((size_t) l1 < sizeof(buf1));
/* Short read. This hence was the last block in the first file, and then came
* EOF. Read one byte more in the second file, so that we can verify we hit EOF there
* too. */
assert((size_t) (l1 + 1) <= sizeof(buf2));
l2 = read(new_fd, buf2, l1 + 1);
}
if (l2 != l1)
goto do_rename;
if (memcmp(buf1, buf2, l1) != 0)
goto do_rename;
if ((size_t) l1 < sizeof(buf1)) /* We hit EOF on the first file, and the second file too, hence exit
* now. */
break;
}
is_same: