fix: upload part tmp+rename (B4), transactional last-admin DeleteUser (B5), RowsAffected order (B13)

This commit is contained in:
2026-09-14 19:42:11 +08:00
parent 8fbc58eaaa
commit b82a891c50
4 changed files with 108 additions and 27 deletions
+10 -2
View File
@@ -198,8 +198,11 @@ func (h *H) UploadPart(c *gin.Context) {
}
lo, hi := chunkRange(m, idx)
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, hi-lo)
// B4: write to .tmp then rename — prevents truncated parts from being
// reported as "received" by UploadStatus if the process crashes mid-write.
p := filepath.Join(dir, "parts", strconv.FormatInt(idx, 10))
f, e := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
tmp := p + ".tmp"
f, e := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
if e != nil {
err(c, http.StatusInternalServerError, "internal", "create part")
return
@@ -207,7 +210,7 @@ func (h *H) UploadPart(c *gin.Context) {
n, e := io.Copy(f, c.Request.Body)
f.Close()
if e != nil || n != hi-lo {
os.Remove(p)
os.Remove(tmp)
var mbe *http.MaxBytesError
code, msg := "too_large", "part size mismatch"
if errors.As(e, &mbe) {
@@ -216,6 +219,11 @@ func (h *H) UploadPart(c *gin.Context) {
err(c, http.StatusRequestEntityTooLarge, code, msg)
return
}
if e := os.Rename(tmp, p); e != nil {
os.Remove(tmp)
err(c, http.StatusInternalServerError, "internal", "rename part")
return
}
c.JSON(http.StatusAccepted, gin.H{"accepted": true})
}