WebUI: a batch upload cut short removes its partial file before it answers

A batch stream that ends inside a file left that file's .upload- temporary
until the request was freed, after the 400 answer was sent: a client reading
the folder the moment the answer arrived could still find it. The gate's
test_batch_refuses_bad_names_and_bad_streams did, once, with the gates run on
four CPUs (taskset -c 0-3). BatchUpload::abandon() now closes and removes the
cut file before the answer; the destructor calls the same.

Evidence: JOBS=4 taskset -c 0-3 nice -n 10 bash tools/verify.sh: the unit
gate failed on that test before (a .upload- file left in content/batch-c)
and passed after (197 tests OK, 1 skipped); python3 -m unittest
tests.test_webui: 17 tests OK.
This commit is contained in:
Mihawk committed 2026-10-17 18:20:49 -04:00
1 parent 90848c40d9
commit ae5edabb37
1 file changed
+11 -1
+11 -1
View File
@@ -1187,13 +1187,19 @@ struct BatchUpload final : ps5_transfer::BatchSink
else
fail("cannot finish");
}
~BatchUpload() override
/* The file a cut stream was in the middle of goes */
void abandon()
{
const int fd = writer.release();
if (fd >= 0)
close(fd);
if (!temporary.empty())
unlink(temporary.c_str());
temporary.clear();
}
~BatchUpload() override
{
abandon();
}
};
struct BatchState
@@ -1970,6 +1976,10 @@ MHD_Result transfer_route(MHD_Connection *c, const std::string &url, const std::
failed += (failed.size() > 1 ? "," : "") + std::string("{\"name\":") + quote(f.first) +
",\"error\":" + quote(f.second) + '}';
const bool whole = state->reader.finished() && r.received == r.expected;
/* Before the answer, not when the request is freed after it: a client that reads
* the folder the moment the answer arrives must not find the partial file. */
if (!whole)
b.abandon();
return respond(c, whole ? 200 : 400,
"{\"complete\":" + std::string(whole ? "true" : "false") + ",\"written\":" +
std::to_string(b.written) + ",\"skipped\":" + std::to_string(b.skipped) +