123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- #include "platform.h"
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #include "crypto.h"
- #include "netpacket.h"
- #include "netproto.h"
- #include "storage_internal.h"
- #include "tsnetwork.h"
- #include "warnp.h"
- #include "storage.h"
- /*
- * Maximum number of delete operations which are allowed to be pending
- * before storage_delete_file will block.
- */
- #define MAXPENDING_DELETE 1024
- struct storage_delete_internal {
- /* Transaction parameters. */
- NETPACKET_CONNECTION * NPC;
- uint64_t machinenum;
- uint8_t nonce[32];
- /* Are we not allowed to delete files? */
- int readonly;
- /* Number of pending deletes. */
- size_t npending;
- };
- struct delete_file_internal {
- /* Pointer to transaction to which this belongs. */
- struct storage_delete_internal * S;
- /* General state information. */
- uint64_t machinenum;
- int done;
- /* Parameters used in delete_file. */
- uint8_t class;
- uint8_t name[32];
- uint8_t nonce[32];
- };
- static sendpacket_callback callback_delete_file_send;
- static handlepacket_callback callback_delete_file_response;
- /**
- * storage_delete_start(machinenum, lastseq, seqnum):
- * Start a delete transaction, presuming that ${lastseq} is the sequence
- * number of the last committed transaction, or zeroes if there is no
- * previous transaction; and store the sequence number of the new transaction
- * into ${seqnum}.
- */
- STORAGE_D *
- storage_delete_start(uint64_t machinenum, const uint8_t lastseq[32],
- uint8_t seqnum[32])
- {
- struct storage_delete_internal * S;
- /* Allocate memory. */
- if ((S = malloc(sizeof(struct storage_delete_internal))) == NULL)
- goto err0;
- /* Store machine number. */
- S->machinenum = machinenum;
- /* No pending deletes so far. */
- S->npending = 0;
- /* This is not readonly. */
- S->readonly = 0;
- /* Open netpacket connection. */
- if ((S->NPC = netpacket_open(USERAGENT)) == NULL)
- goto err1;
- /* Start a delete transaction. */
- if (storage_transaction_start_delete(S->NPC, machinenum, lastseq,
- S->nonce))
- goto err2;
- /* Copy the transaction nonce out. */
- memcpy(seqnum, S->nonce, 32);
- /* Success! */
- return (S);
- err2:
- netpacket_close(S->NPC);
- err1:
- free(S);
- err0:
- /* Failure! */
- return (NULL);
- }
- /**
- * storage_fsck_start(machinenum, seqnum, readonly, whichkey):
- * Start a fsck transaction, and store the sequence number of said
- * transaction into ${seqnum}. If ${whichkey} is zero, use the write key
- * (in which case the transaction must be readonly).
- */
- STORAGE_D *
- storage_fsck_start(uint64_t machinenum, uint8_t seqnum[32],
- int readonly, uint8_t whichkey)
- {
- struct storage_delete_internal * S;
- /* Allocate memory. */
- if ((S = malloc(sizeof(struct storage_delete_internal))) == NULL)
- goto err0;
- /* Store machine number. */
- S->machinenum = machinenum;
- /* No pending deletes so far. */
- S->npending = 0;
- /* This is not readonly. */
- S->readonly = readonly;
- /* Open netpacket connection. */
- if ((S->NPC = netpacket_open(USERAGENT)) == NULL)
- goto err1;
- /* Start a delete transaction. */
- if (storage_transaction_start_fsck(S->NPC, machinenum, S->nonce,
- whichkey))
- goto err2;
- /* Copy the transaction nonce out. */
- memcpy(seqnum, S->nonce, 32);
- /* Success! */
- return (S);
- err2:
- netpacket_close(S->NPC);
- err1:
- free(S);
- err0:
- /* Failure! */
- return (NULL);
- }
- /**
- * storage_delete_file(S, class, name):
- * Delete the file ${name} from class ${class} as part of the delete
- * transaction associated with the cookie ${S}.
- */
- int
- storage_delete_file(STORAGE_D * S, char class, const uint8_t name[32])
- {
- struct delete_file_internal * C;
- if (S->readonly) {
- warn0("Not pruning corrupted data; please run --fsck-prune");
- goto err0;
- }
- /* Create delete cookie. */
- if ((C = malloc(sizeof(struct delete_file_internal))) == NULL)
- goto err0;
- C->S = S;
- C->machinenum = S->machinenum;
- C->class = (uint8_t)class;
- memcpy(C->name, name, 32);
- memcpy(C->nonce, S->nonce, 32);
- C->done = 0;
- /* We're issuing a delete operation. */
- S->npending += 1;
- /*
- * Make sure the pending operation queue isn't too large before we
- * add yet another operation to it.
- */
- if (S->npending > MAXPENDING_DELETE) {
- /* Avoid silly window syndrome. */
- while (S->npending > MAXPENDING_DELETE / 2 + 1) {
- if (network_select(1))
- goto err1;
- }
- }
- /* Ask the netpacket layer to send a request and get a response. */
- if (netpacket_op(S->NPC, callback_delete_file_send, C))
- goto err0;
- /* Success! */
- return (0);
- err1:
- free(C);
- err0:
- /* Failure! */
- return (-1);
- }
- static int
- callback_delete_file_send(void * cookie, NETPACKET_CONNECTION * NPC)
- {
- struct delete_file_internal * C = cookie;
- /* Ask the server to delete the file in question. */
- return (netpacket_delete_file(NPC, C->machinenum, C->class,
- C->name, C->nonce, callback_delete_file_response));
- }
- static int
- callback_delete_file_response(void * cookie,
- NETPACKET_CONNECTION * NPC, int status, uint8_t packettype,
- const uint8_t * packetbuf, size_t packetlen)
- {
- struct delete_file_internal * C = cookie;
- (void)packetlen; /* UNUSED */
- (void)NPC; /* UNUSED */
- /* Handle errors. */
- if (status != NETWORK_STATUS_OK) {
- netproto_printerr(status);
- goto err1;
- }
- /* Make sure we received the right type of packet. */
- if (packettype != NETPACKET_DELETE_FILE_RESPONSE)
- goto err2;
- /* Verify packet hmac. */
- switch (netpacket_hmac_verify(packettype, C->nonce,
- packetbuf, 34, CRYPTO_KEY_AUTH_DELETE)) {
- case 1:
- goto err2;
- case -1:
- goto err1;
- }
- /* Make sure that the packet corresponds to the right file. */
- if ((packetbuf[1] != C->class) ||
- (memcmp(&packetbuf[2], C->name, 32)))
- goto err2;
- /* Parse status returned by server. */
- switch (packetbuf[0]) {
- case 0:
- /* This delete operation is no longer pending. */
- C->S->npending -= 1;
- break;
- case 1:
- warn0("Cannot delete file: File does not exist");
- goto err1;
- case 2:
- /* Bad nonce. */
- warn0("Delete transaction interrupted");
- goto err1;
- default:
- goto err2;
- }
- /* Free delete cookie. */
- free(C);
- /* Success! */
- return (0);
- err2:
- netproto_printerr(NETPROTO_STATUS_PROTERR);
- err1:
- free(C);
- /* Failure! */
- return (-1);
- }
- /**
- * storage_delete_flush(S):
- * Make sure all operations performed as part of the transaction associated
- * with the cookie ${S} have been safely stored in preparation for being
- * committed.
- */
- int
- storage_delete_flush(STORAGE_D * S)
- {
- /* Wait until all pending deletes have been completed. */
- while (S->npending > 0) {
- if (network_select(1))
- goto err0;
- }
- /* Success! */
- return (0);
- err0:
- /* Failure! */
- return (-1);
- }
- /**
- * storage_delete_end(S):
- * Make sure that all operations performed as part of the transaction
- * associated with the cookie ${S} have been safely stored in
- * preparation for being committed; and close the transaction and free
- * associated memory.
- */
- int
- storage_delete_end(STORAGE_D * S)
- {
- /* Flush any pending deletes. */
- if (storage_delete_flush(S))
- goto err2;
- /* Close netpacket connection. */
- if (netpacket_close(S->NPC))
- goto err1;
- /* Free structure. */
- free(S);
- /* Success! */
- return (0);
- err2:
- netpacket_close(S->NPC);
- err1:
- free(S);
- /* Failure! */
- return (-1);
- }
- /**
- * storage_delete_free(S):
- * Free any memory allocated as part of the delete transaction associated
- * with the cookie ${S}; the transaction will not be committed.
- */
- void
- storage_delete_free(STORAGE_D * S)
- {
- /* Behave consistently with free(NULL). */
- if (S == NULL)
- return;
- /* Close netpacket connection. */
- netpacket_close(S->NPC);
- /* Free structure. */
- free(S);
- }
|