Apply storage policy before cancellation and physical retirement
This commit is contained in:
1 parent
d5f3f74ba5
commit
c5c6d96384
1 file changed
+30
-27
+30
-27
@@ -1002,24 +1002,35 @@ static void dm_custody_remove(struct dm_media_state* media, const uint8_t id[16]
|
||||
media_async_submit(media->inst->media_async, media->inst->ua, dm_file_work, job, dm_file_done, job);
|
||||
}
|
||||
|
||||
/* Подпись B позволяет любому авторизованному S завершить удаление точного артефакта. */
|
||||
/* Все факты уже проверены и сохранены. Терминальное состояние предшествует отмене I/O. */
|
||||
static int dm_custody_complete(struct UTUN_INSTANCE* inst, const uint8_t id[16], int policy) {
|
||||
int done = dm_media_retention_done(inst, id, policy);
|
||||
if (done <= 0) return done;
|
||||
sqlite3_stmt* st = dm_media_prepare(inst, policy ?
|
||||
"UPDATE dm_custody SET ready=-1,retry_at=0,receipt=(SELECT taken FROM dm_file_targets"
|
||||
" WHERE id=? AND side=1 AND taken IS NOT NULL LIMIT 1) WHERE id=? AND ready>=0" :
|
||||
"UPDATE dm_custody SET ready=-1,retry_at=0,receipt=(SELECT received FROM dm_file_targets"
|
||||
" WHERE id=? AND side=1 AND received IS NOT NULL LIMIT 1) WHERE id=? AND ready>=0");
|
||||
if (!st) return -1;
|
||||
sqlite3_bind_blob(st, 1, id, 16, SQLITE_STATIC); sqlite3_bind_blob(st, 2, id, 16, SQLITE_STATIC);
|
||||
if (dm_media_step(inst, st)) return -1;
|
||||
if (sqlite3_changes(inst->topo_sqlite_db)) DEBUG_INFO(DEBUG_CATEGORY_DM, "DM custody: retention complete delete_on_open=%d", policy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* DELETE переносит факт; удаление определяет сохранённая политика M. */
|
||||
static void dm_custody_delete(struct UTUN_INSTANCE* inst, uint64_t group, uint64_t source, const uint8_t* r) {
|
||||
if (dm_media_verify_receipt(inst, r, NULL, 0)) return;
|
||||
uint64_t author, recipient;
|
||||
memcpy(&author, r + 24, 8); memcpy(&recipient, r + 32, 8);
|
||||
/* Для существующей копии точная подпись B разрешает удаление даже после отзыва роли M/S. */
|
||||
sqlite3_stmt* st = dm_media_prepare(inst, "SELECT body FROM dm_custody WHERE id=?");
|
||||
sqlite3_stmt* st = dm_media_prepare(inst, "SELECT body,delete_on_open FROM dm_custody WHERE id=?");
|
||||
if (!st) return;
|
||||
sqlite3_bind_blob(st, 1, r + 40, 16, SQLITE_STATIC);
|
||||
int rc = sqlite3_step(st);
|
||||
if (rc == SQLITE_ROW) {
|
||||
int valid = !dm_media_verify_receipt(inst, r, sqlite3_column_blob(st, 0), (size_t)sqlite3_column_bytes(st, 0));
|
||||
int policy = sqlite3_column_int(st, 1);
|
||||
int valid = !dm_media_receipt_save(inst, r, sqlite3_column_blob(st, 0), (size_t)sqlite3_column_bytes(st, 0));
|
||||
sqlite3_finalize(st);
|
||||
if (!valid) return;
|
||||
st = dm_media_prepare(inst, "UPDATE dm_custody SET ready=-1,receipt=?,retry_at=0 WHERE id=?");
|
||||
if (!st) return;
|
||||
sqlite3_bind_blob(st, 1, r, DM_MEDIA_RECEIPT_SIZE, SQLITE_STATIC); sqlite3_bind_blob(st, 2, r + 40, 16, SQLITE_STATIC);
|
||||
if (dm_media_step(inst, st)) return;
|
||||
if (!valid || dm_custody_complete(inst, r + 40, policy) != 1) return;
|
||||
file_transfer_cancel_object(inst->file_transfer, r + 40);
|
||||
dm_custody_remove(inst->dm_media, r + 40);
|
||||
return;
|
||||
@@ -1030,20 +1041,11 @@ static void dm_custody_delete(struct UTUN_INSTANCE* inst, uint64_t group, uint64
|
||||
if (!st) return;
|
||||
sqlite3_bind_blob(st, 1, r + 40, 16, SQLITE_STATIC);
|
||||
rc = sqlite3_step(st);
|
||||
int exact = rc == SQLITE_DONE || (rc == SQLITE_ROW && sqlite3_column_bytes(st, 0) == 32 &&
|
||||
!memcmp(sqlite3_column_blob(st, 0), r + 56, 32));
|
||||
int exact = rc == SQLITE_ROW && sqlite3_column_bytes(st, 0) == 32 && !memcmp(sqlite3_column_blob(st, 0), r + 56, 32);
|
||||
sqlite3_finalize(st);
|
||||
if (!exact) { DEBUG_WARN(DEBUG_CATEGORY_DM, "dm_media: delete conflicts with retired artifact"); return; }
|
||||
if (rc == SQLITE_DONE && (!dm_media_scope(inst, group, source, "supernode", author, recipient) ||
|
||||
!dm_media_scope(inst, group, inst->node_id, "storage", author, recipient))) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_DM, "dm_media: unknown DELETE without custody grant source=%llu", (unsigned long long)source); return;
|
||||
}
|
||||
st = dm_media_prepare(inst, "INSERT INTO dm_custody_done(id,body_hash,receipt) VALUES(?,?,?)"
|
||||
" ON CONFLICT(id) DO UPDATE SET receipt=excluded.receipt");
|
||||
if (!st) return;
|
||||
sqlite3_bind_blob(st, 1, r + 40, 16, SQLITE_STATIC); sqlite3_bind_blob(st, 2, r + 56, 32, SQLITE_STATIC);
|
||||
sqlite3_bind_blob(st, 3, r, DM_MEDIA_RECEIPT_SIZE, SQLITE_STATIC);
|
||||
if (!dm_media_step(inst, st)) dm_media_send(inst, group, source, DM_MEDIA_DELETE_ACK, r + 40, 16);
|
||||
if (exact) dm_media_send(inst, group, source, DM_MEDIA_DELETE_ACK, r + 40, 16);
|
||||
else if (rc == SQLITE_DONE) DEBUG_DEBUG(DEBUG_CATEGORY_DM, "DM custody: fact before STORE; S retains it for retry");
|
||||
else DEBUG_WARN(DEBUG_CATEGORY_DM, "dm_media: delete conflicts with retired artifact rc=%d", rc);
|
||||
}
|
||||
|
||||
/* OFFER не меняет идентичность беседы. Чужой holder допустим только от S. */
|
||||
@@ -1092,7 +1094,7 @@ static void dm_media_control(struct UTUN_INSTANCE* inst, uint64_t group, uint64_
|
||||
if (author == inst->node_id) {
|
||||
dm_media_accept_receipt(inst, p);
|
||||
} else dm_mailbox_media_recv(dm_mailbox_get_media(inst), group, source, cmd, p, len);
|
||||
} else if ((cmd == DM_MEDIA_STORED && len == 24) || (cmd == DM_MEDIA_DELETE_ACK && len == 16) ||
|
||||
} else if (((cmd == DM_MEDIA_STORED || cmd == DM_MEDIA_RESERVED) && len == 25) || (cmd == DM_MEDIA_DELETE_ACK && len == 16) ||
|
||||
(cmd == DM_MEDIA_EXPIRED && len == 16) || (cmd == DM_MEDIA_REJECT && len == 17)) {
|
||||
dm_mailbox_media_recv(dm_mailbox_get_media(inst), group, source, cmd, p, len);
|
||||
if (cmd == DM_MEDIA_EXPIRED) {
|
||||
@@ -1184,7 +1186,7 @@ static void dm_files_tick(struct dm_media_state* media, uint64_t now) {
|
||||
static void dm_custody_tick(struct dm_media_state* media, uint64_t now) {
|
||||
struct UTUN_INSTANCE* inst = media->inst;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
sqlite3_stmt* st = dm_media_prepare(inst, "SELECT id,body,author,supernode,group_id,expires,ready FROM dm_custody"
|
||||
sqlite3_stmt* st = dm_media_prepare(inst, "SELECT id,body,author,supernode,group_id,expires,ready,delete_on_open FROM dm_custody"
|
||||
" WHERE retry_at<=? ORDER BY retry_at LIMIT 1");
|
||||
if (!st) return;
|
||||
sqlite3_bind_int64(st, 1, (sqlite3_int64)now);
|
||||
@@ -1200,7 +1202,9 @@ static void dm_custody_tick(struct dm_media_state* media, uint64_t now) {
|
||||
uint64_t author = (uint64_t)sqlite3_column_int64(st, 2), super = (uint64_t)sqlite3_column_int64(st, 3);
|
||||
uint64_t group = (uint64_t)sqlite3_column_int64(st, 4), expires = (uint64_t)sqlite3_column_int64(st, 5);
|
||||
int ready = sqlite3_column_int(st, 6);
|
||||
int policy = sqlite3_column_int(st, 7);
|
||||
sqlite3_finalize(st);
|
||||
if (ready >= 0 && dm_custody_complete(inst, id, policy) == 1) ready = -1;
|
||||
st = dm_media_prepare(inst, "UPDATE dm_custody SET retry_at=?,ready=CASE WHEN expires<=? THEN -1 ELSE ready END WHERE id=?");
|
||||
if (!st) return;
|
||||
sqlite3_bind_int64(st, 1, (sqlite3_int64)(now + 5)); sqlite3_bind_int64(st, 2, (sqlite3_int64)now);
|
||||
@@ -1214,8 +1218,7 @@ static void dm_custody_tick(struct dm_media_state* media, uint64_t now) {
|
||||
uint64_t gid = group;
|
||||
if (desc && dm_route_group(inst, author, group, &gid)) dm_file_pull(media, 1, gid, author, desc, author);
|
||||
} else {
|
||||
uint8_t stored[24]; memcpy(stored, id, 16); memcpy(stored + 16, &expires, 8);
|
||||
dm_media_send(inst, group, super, DM_MEDIA_STORED, stored, sizeof(stored));
|
||||
dm_custody_status(inst, group, super, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user