static int send_encrypted_block (BlockTxServer *server, BlockHandle *handle, const char *block_id, int size) { int n, remain; int ret = 0; EVP_CIPHER_CTX ctx; char send_buf[SEND_BUFFER_SIZE]; if (server->version == 1) blocktx_encrypt_init (&ctx, server->key, server->iv); else if (server->version == 2) blocktx_encrypt_init (&ctx, server->key_v2, server->iv_v2); if (send_encrypted_data_frame_begin (server->data_fd, size) < 0) { seaf_warning ("Send block %s: failed to begin.\n", block_id); ret = -1; goto out; } remain = size; while (remain > 0) { n = seaf_block_manager_read_block (seaf->block_mgr, handle, send_buf, SEND_BUFFER_SIZE); if (n < 0) { seaf_warning ("Failed to read block %s.\n", block_id); ret = -1; goto out; } if (send_encrypted_data (&ctx, server->data_fd, send_buf, n) < 0) { seaf_warning ("Send block %s: failed to send data.\n", block_id); ret = -1; goto out; } remain -= n; } if (send_encrypted_data_frame_end (&ctx, server->data_fd) < 0) { seaf_warning ("Send block %s: failed to end.\n", block_id); ret = -1; goto out; } seaf_debug ("Send block %s done.\n", server->curr_block_id); out: EVP_CIPHER_CTX_cleanup (&ctx); return ret; }
static int test_block_manager () { SeafBlockManager *mgr = seaf->block_mgr; char *block_id = "c882e263e9d02c63ca6b61c68508761cbc74c358"; char wr_buf[1024], rd_buf[1024]; BlockHandle *handle; BlockMetadata *md; int n; printf ("\n=== Test block manager\n\n"); memset (wr_buf, 1, sizeof(wr_buf)); handle = seaf_block_manager_open_block (mgr, block_id, BLOCK_WRITE); g_assert (handle != NULL); n = seaf_block_manager_write_block (mgr, handle, wr_buf, sizeof(wr_buf)); g_assert (n == sizeof(wr_buf)); md = seaf_block_manager_stat_block_by_handle (mgr, handle); g_assert (md->size == sizeof(wr_buf)); g_free (md); g_assert (seaf_block_manager_close_block(mgr, handle) == 0); g_assert (seaf_block_manager_commit_block(mgr, handle) == 0); seaf_block_manager_block_handle_free (mgr, handle); handle = seaf_block_manager_open_block (mgr, block_id, BLOCK_READ); g_assert (handle != NULL); n = seaf_block_manager_read_block (mgr, handle, rd_buf, sizeof(rd_buf)); g_assert (n == sizeof(rd_buf)); md = seaf_block_manager_stat_block_by_handle (mgr, handle); g_assert (md->size == sizeof(wr_buf)); g_free (md); g_assert (seaf_block_manager_close_block(mgr, handle) == 0); seaf_block_manager_block_handle_free (mgr, handle); g_assert (memcmp (wr_buf, rd_buf, sizeof(wr_buf)) == 0); md = seaf_block_manager_stat_block (mgr, block_id); g_assert (strcmp (md->id, block_id) == 0); g_assert (md->size == sizeof(wr_buf)); g_free (md); return 0; }
gboolean seaf_block_manager_verify_block (SeafBlockManager *mgr, const char *store_id, int version, const char *block_id, gboolean *io_error) { BlockHandle *h; char buf[10240]; int n; SHA_CTX ctx; guint8 sha1[20]; char check_id[41]; h = seaf_block_manager_open_block (mgr, store_id, version, block_id, BLOCK_READ); if (!h) { seaf_warning ("Failed to open block %.8s.\n", block_id); *io_error = TRUE; return FALSE; } SHA1_Init (&ctx); while (1) { n = seaf_block_manager_read_block (mgr, h, buf, sizeof(buf)); if (n < 0) { seaf_warning ("Failed to read block %.8s.\n", block_id); *io_error = TRUE; return FALSE; } if (n == 0) break; SHA1_Update (&ctx, buf, n); } seaf_block_manager_close_block (mgr, h); seaf_block_manager_block_handle_free (mgr, h); SHA1_Final (sha1, &ctx); rawdata_to_hex (sha1, check_id, 20); if (strcmp (check_id, block_id) == 0) return TRUE; else return FALSE; }
static gboolean write_nonenc_block_to_file (const char *repo_id, int version, const char *block_id, int fd, const char *path) { BlockHandle *handle; char buf[64 * 1024]; gboolean ret = TRUE; int n; handle = seaf_block_manager_open_block (seaf->block_mgr, repo_id, version, block_id, BLOCK_READ); if (!handle) { return FALSE; } while (1) { n = seaf_block_manager_read_block (seaf->block_mgr, handle, buf, sizeof(buf)); if (n < 0) { seaf_warning ("Failed to read block %s.\n", block_id); ret = FALSE; break; } else if (n == 0) { break; } if (writen (fd, buf, n) != n) { seaf_warning ("Failed to write block %s to file %s.\n", block_id, path); ret = FALSE; break; } } seaf_block_manager_close_block (seaf->block_mgr, handle); seaf_block_manager_block_handle_free (seaf->block_mgr, handle); return ret; }
static int send_encrypted_block (BlockTxClient *client, BlockHandle *handle, const char *block_id) { BlockTxInfo *info = client->info; BlockMetadata *md; int size, n, remain; int ret = 0; EVP_CIPHER_CTX ctx; char send_buf[SEND_BUFFER_SIZE]; md = seaf_block_manager_stat_block_by_handle (seaf->block_mgr, handle); if (!md) { seaf_warning ("Failed to stat block %s.\n", block_id); client->info->result = BLOCK_CLIENT_FAILED; ret = -1; goto out; } size = md->size; g_free (md); if (client->version == 1) blocktx_encrypt_init (&ctx, client->key, client->iv); else if (client->version == 2) blocktx_encrypt_init (&ctx, client->key_v2, client->iv_v2); if (send_encrypted_data_frame_begin (client->data_fd, size) < 0) { seaf_warning ("Send block %s: failed to begin.\n", block_id); info->result = BLOCK_CLIENT_NET_ERROR; ret = -1; goto out; } remain = size; while (remain > 0) { if (info->task->state == TASK_STATE_CANCELED) { info->result = BLOCK_CLIENT_CANCELED; ret = -1; goto out; } n = seaf_block_manager_read_block (seaf->block_mgr, handle, send_buf, SEND_BUFFER_SIZE); if (n < 0) { seaf_warning ("Failed to read block %s.\n", block_id); info->result = BLOCK_CLIENT_FAILED; ret = -1; goto out; } if (send_encrypted_data (&ctx, client->data_fd, send_buf, n) < 0) { seaf_warning ("Send block %s: failed to send data.\n", block_id); info->result = BLOCK_CLIENT_NET_ERROR; ret = -1; goto out; } /* Update global transferred bytes. */ g_atomic_int_add (&(info->task->tx_bytes), n); g_atomic_int_add (&(seaf->sync_mgr->sent_bytes), n); /* If uploaded bytes exceeds the limit, wait until the counter * is reset. We check the counter every 100 milliseconds, so we * can waste up to 100 milliseconds without sending data after * the counter is reset. */ while (1) { gint sent = g_atomic_int_get(&(seaf->sync_mgr->sent_bytes)); if (seaf->sync_mgr->upload_limit > 0 && sent > seaf->sync_mgr->upload_limit) /* 100 milliseconds */ G_USLEEP (100000); else break; } remain -= n; } if (send_encrypted_data_frame_end (&ctx, client->data_fd) < 0) { seaf_warning ("Send block %s: failed to end.\n", block_id); info->result = BLOCK_CLIENT_NET_ERROR; ret = -1; goto out; } out: EVP_CIPHER_CTX_cleanup (&ctx); return ret; }
int read_file(SeafileSession *seaf, Seafile *file, char *buf, size_t size, off_t offset, struct fuse_file_info *info) { BlockHandle *handle = NULL;; BlockMetadata *bmd; char *blkid; char *ptr; off_t off = 0, nleft; int i, n, ret = -EIO; for (i = 0; i < file->n_blocks; i++) { blkid = file->blk_sha1s[i]; bmd = seaf_block_manager_stat_block(seaf->block_mgr, blkid); if (!bmd) return -EIO; if (offset < off + bmd->size) { g_free (bmd); break; } off += bmd->size; g_free (bmd); } /* beyond the file size */ if (i == file->n_blocks) return 0; nleft = size; ptr = buf; while (nleft > 0 && i < file->n_blocks) { blkid = file->blk_sha1s[i]; handle = seaf_block_manager_open_block(seaf->block_mgr, blkid, BLOCK_READ); if (!handle) { seaf_warning ("Failed to open block %s.\n", blkid); return -EIO; } /* trim the offset in a block */ if (offset > off) { char *tmp = (char *)malloc(sizeof(char) * (offset - off)); if (!tmp) return -ENOMEM; n = seaf_block_manager_read_block(seaf->block_mgr, handle, tmp, offset-off); if (n != offset - off) { seaf_warning ("Failed to read block %s.\n", blkid); free (tmp); goto out; } off += n; free(tmp); } if ((n = seaf_block_manager_read_block(seaf->block_mgr, handle, ptr, nleft)) < 0) { seaf_warning ("Failed to read block %s.\n", blkid); goto out; } nleft -= n; ptr += n; off += n; ++i; /* At this point we should have read all the content of the block or * have read up to @size bytes. So it's safe to close the block. */ seaf_block_manager_close_block(seaf->block_mgr, handle); seaf_block_manager_block_handle_free (seaf->block_mgr, handle); } return size - nleft; out: if (handle) { seaf_block_manager_close_block(seaf->block_mgr, handle); seaf_block_manager_block_handle_free (seaf->block_mgr, handle); } return ret; }