148 lines
2.9 KiB
C
148 lines
2.9 KiB
C
#include <libcbd.h>
|
|
|
|
#include <cbdutil.h>
|
|
|
|
uint verbose_level;
|
|
|
|
void __attribute__((noreturn))
|
|
error(const char* fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
vfprintf(stderr, fmt, ap);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
int
|
|
verbose(uint level, const char* fmt, ...)
|
|
{
|
|
int ret = 0;
|
|
va_list ap;
|
|
|
|
if (verbose_level >= level) {
|
|
va_start(ap, fmt);
|
|
vprintf(fmt, ap);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool
|
|
ask_user_bool(tristate_t auto_response, const char* fmt, ...)
|
|
{
|
|
va_list ap;
|
|
char prompt[256];
|
|
char* line;
|
|
size_t len;
|
|
int ret;
|
|
bool answer;
|
|
|
|
va_start(ap, fmt);
|
|
vsnprintf(prompt, sizeof(prompt), fmt, ap);
|
|
va_end(ap);
|
|
again:
|
|
printf("%s [y/n]? ", prompt);
|
|
if (auto_response != t_none) {
|
|
answer = (auto_response == t_true);
|
|
printf("%s\n", (answer ? "y" : "n"));
|
|
return answer;
|
|
}
|
|
line = NULL;
|
|
len = 0;
|
|
getline(&line, &len, stdin);
|
|
if (ret > 0) {
|
|
switch (line[0]) {
|
|
case 'y':
|
|
case 'Y':
|
|
answer = true;
|
|
break;
|
|
case 'n':
|
|
case 'N':
|
|
answer = false;
|
|
break;
|
|
default:
|
|
ret = -1;
|
|
}
|
|
}
|
|
free(line);
|
|
if (ret <= 0) {
|
|
goto again;
|
|
}
|
|
|
|
return answer;
|
|
}
|
|
|
|
void
|
|
pblk_read(int fd, u64 pblk, u32 count, u8* data)
|
|
{
|
|
off_t pos;
|
|
size_t remain;
|
|
ssize_t ret;
|
|
|
|
pos = lseek(fd, pblk * PBLK_SIZE, SEEK_SET);
|
|
if (pos == (off_t)-1) {
|
|
error("Failed to seek\n");
|
|
}
|
|
|
|
remain = count * PBLK_SIZE;
|
|
while (remain) {
|
|
ret = read(fd, data, remain);
|
|
if (ret <= 0) {
|
|
error("Failed to read\n");
|
|
}
|
|
remain -= ret;
|
|
data += ret;
|
|
}
|
|
}
|
|
|
|
void
|
|
pblk_write(int fd, u64 pblk, u32 count, const u8* data)
|
|
{
|
|
off_t pos;
|
|
size_t remain;
|
|
ssize_t ret;
|
|
|
|
pos = lseek(fd, pblk * PBLK_SIZE, SEEK_SET);
|
|
if (pos == (off_t)-1) {
|
|
error("Failed to seek\n");
|
|
}
|
|
|
|
remain = count * PBLK_SIZE;
|
|
while (remain) {
|
|
ret = write(fd, data, remain);
|
|
if (ret <= 0) {
|
|
error("Failed to write\n");
|
|
}
|
|
remain -= ret;
|
|
data += ret;
|
|
}
|
|
}
|
|
|
|
void
|
|
cbd_check_header(const struct cbd_header* header)
|
|
{
|
|
enum cbd_alg alg = cbd_compression_alg_get(&header->params);
|
|
u8 level = cbd_compression_level_get(&header->params);
|
|
|
|
if (memcmp(header->magic, CBD_MAGIC, sizeof(header->magic))) {
|
|
error("Bad magic\n");
|
|
}
|
|
if (header->version_major != CBD_VERSION_MAJOR) {
|
|
error("Bad major version\n");
|
|
}
|
|
if (header->version_minor != CBD_VERSION_MINOR) {
|
|
error("Bad major version\n");
|
|
}
|
|
if (alg == CBD_ALG_NONE || alg >= CBD_ALG_MAX) {
|
|
error("Bad algorithm\n");
|
|
}
|
|
if (level < 1 || level > 9) {
|
|
error("Bad compression\n");
|
|
}
|
|
if (header->params.lblk_shift < LBLK_SHIFT_MIN ||
|
|
header->params.lblk_shift >= LBLK_SHIFT_MAX) {
|
|
error("Bad logical block shift\n");
|
|
}
|
|
}
|