Publish attachment output once and preserve ownership through cancellation
This commit is contained in:
1 parent
92d52d25a8
commit
4350b54769
2 files changed
+24
-15
No files matched your search
+19
-10
@@ -23,11 +23,13 @@ enum { AK_REQUEST = 1, AK_REQUEST_ACK, AK_GRANT, AK_DENY, AK_RESULT_ACK };
|
||||
|
||||
struct ak_file {
|
||||
struct UTUN_INSTANCE* inst;
|
||||
char channel[32], source[1024], cipher[1024], plain[1024], temporary[1040], type[32];
|
||||
char channel[32], source[1024], cipher[1024], plain[1024], type[32];
|
||||
struct file_io_temp output; // Единственный собственный temp; стабильный адрес до completion.
|
||||
uint8_t id[16], key[32], message[32], hash[32], reply[32];
|
||||
struct attachment_info info;
|
||||
uint64_t author, request;
|
||||
int encrypt, error;
|
||||
int plain_prepared, published; // Только реально подготовленный snapshot и выполненный rename дают право очистки.
|
||||
};
|
||||
|
||||
/* Все ошибки SQLite содержат конкретную операцию. */
|
||||
@@ -121,12 +123,18 @@ static int ak_parent(const char* path) {
|
||||
static void ak_file_work(void* arg) {
|
||||
struct ak_file* job = arg; job->error = -1;
|
||||
if (ak_parent(job->plain) || ak_parent(job->cipher)) return;
|
||||
snprintf(job->temporary, sizeof(job->temporary), "%s.part", job->encrypt ? job->cipher : job->plain);
|
||||
if (job->encrypt) {
|
||||
if (ma_copy_file(job->source, job->plain) || encrypted_file_sync(job->plain) || encrypted_file_sync_directory(job->plain) ||
|
||||
encrypted_file_write(job->plain, job->temporary, job->key, job->author, job->id, &job->info, job->type)) return;
|
||||
} else if (encrypted_file_read(job->cipher, job->temporary, job->key, job->author, job->id, job->hash, &job->info, job->type)) return;
|
||||
if (encrypted_file_publish(job->temporary, job->encrypt ? job->cipher : job->plain)) return;
|
||||
if (ma_copy_file(job->source, job->plain)) return;
|
||||
job->plain_prepared = 1;
|
||||
if (file_io_sync_file(job->plain) || file_io_sync_directory(job->plain) ||
|
||||
encrypted_file_write(job->plain, job->cipher, &job->output, job->key, job->author, job->id, &job->info, job->type)) return;
|
||||
} else if (encrypted_file_read(job->cipher, job->plain, &job->output, job->key, job->author, job->id,
|
||||
job->hash, &job->info, job->type)) return;
|
||||
int error = file_io_temp_publish(&job->output, job->encrypt ? job->plain : job->cipher, job->encrypt ? job->cipher : job->plain);
|
||||
job->published = !job->output.temporary[0]; // Rename уже выполнен и при последующем отказе directory sync.
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_MEDIA, "attachment keys: output publication encrypt=%d installed=%d error=%d",
|
||||
job->encrypt, job->published, error);
|
||||
if (error) return;
|
||||
job->error = 0;
|
||||
}
|
||||
|
||||
@@ -174,11 +182,12 @@ static void ak_file_done(void* arg, int error) {
|
||||
if (job->encrypt) chat_event_submitted(inst, job->request, 0);
|
||||
}
|
||||
if (job->encrypt && remove(job->source) && errno != ENOENT) DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment keys: prepared source cleanup failed");
|
||||
if ((!success || !valid) && job->temporary[0] && remove(job->temporary) && errno != ENOENT)
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment keys: temporary cleanup failed");
|
||||
file_io_temp_discard(&job->output);
|
||||
if (!valid) {
|
||||
if (remove(job->plain) && errno != ENOENT) DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment keys: deleted channel plaintext cleanup failed");
|
||||
if (job->encrypt && remove(job->cipher) && errno != ENOENT) DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment keys: deleted channel ciphertext cleanup failed");
|
||||
if (((job->encrypt && job->plain_prepared) || (!job->encrypt && job->published)) && remove(job->plain) && errno != ENOENT)
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment keys: deleted channel plaintext cleanup failed");
|
||||
if (job->encrypt && job->published && remove(job->cipher) && errno != ENOENT)
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "attachment keys: deleted channel ciphertext cleanup failed");
|
||||
}
|
||||
if (valid) {
|
||||
if (success && !job->encrypt) chat_media_cache_enforce(inst);
|
||||
|
||||
+5
-5
@@ -154,7 +154,7 @@ static void dm_cleanup_pump(struct dm_media_state* media);
|
||||
static void dm_cleanup_work(void* arg) {
|
||||
struct dm_cleanup_job* job = arg;
|
||||
job->error = dm_file_remove(job->path);
|
||||
if (!job->error) job->error = encrypted_file_sync_directory(job->path);
|
||||
if (!job->error) job->error = file_io_sync_directory(job->path);
|
||||
}
|
||||
|
||||
static void dm_cleanup_done(void* arg, int error) {
|
||||
@@ -488,7 +488,7 @@ static void dm_file_work(void* arg) {
|
||||
struct dm_file_job* job = arg;
|
||||
job->error = -1;
|
||||
if (job->work == DM_FILE_DELETE) {
|
||||
if (!dm_file_remove(job->cipher) && !dm_file_remove(job->temp)) job->error = encrypted_file_sync_directory(job->cipher);
|
||||
if (!dm_file_remove(job->cipher) && !dm_file_remove(job->temp)) job->error = file_io_sync_directory(job->cipher);
|
||||
return;
|
||||
}
|
||||
if (job->work == DM_FILE_PREPARE) {
|
||||
@@ -530,9 +530,9 @@ done:
|
||||
if (out && fclose(out)) { DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_media: worker output close failed"); job->error = -1; }
|
||||
if (!job->error) {
|
||||
if (job->work == DM_FILE_PREPARE) {
|
||||
job->error = encrypted_file_publish(job->temp, job->cipher);
|
||||
if (!job->error) job->error = encrypted_file_sync_directory(job->plain);
|
||||
} else job->error = encrypted_file_publish(job->work == DM_FILE_CUSTODY ? job->cipher : job->temp, job->output);
|
||||
job->error = file_io_publish(job->temp, job->cipher);
|
||||
if (!job->error) job->error = file_io_sync_directory(job->plain);
|
||||
} else job->error = file_io_publish(job->work == DM_FILE_CUSTODY ? job->cipher : job->temp, job->output);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user