Example #1
0
int main(int argc, char **argv) {
    config cfg;
    memset(&cfg, 0, sizeof(cfg));
    proc_args(&cfg, argc, argv);

    if (0 == strcmp(cfg.in_fname, cfg.out_fname)
        && (0 != strcmp("-", cfg.in_fname))) {
        fprintf(stderr, "Refusing to overwrite file '%s' with itself.\n", cfg.in_fname);
        exit(1);
    }

    cfg.in = handle_open(cfg.in_fname, IO_READ, cfg.buffer_size);
    if (cfg.in == NULL) { die("Failed to open input file for read"); }
    cfg.out = handle_open(cfg.out_fname, IO_WRITE, cfg.buffer_size);
    if (cfg.out == NULL) { die("Failed to open output file for write"); }

#if _WIN32
    /*
     * On Windows, stdin and stdout default to text mode. Switch them to
     * binary mode before sending data through them.
     */
    _setmode(STDOUT_FILENO, O_BINARY);
    _setmode(STDIN_FILENO, O_BINARY);
#endif

    if (cfg.cmd == OP_ENC) {
        return encode(&cfg);
    } else if (cfg.cmd == OP_DEC) {
        return decode(&cfg);
    } else {
        usage();
    }
}
Example #2
0
static int
handle_socket_msg(struct weston_launch *wl)
{
	char control[CMSG_SPACE(sizeof(int))];
	char buf[BUFSIZ];
	struct msghdr msg;
	struct iovec iov;
	int ret = -1;
	ssize_t len;
	struct weston_launcher_message *message;

	memset(&msg, 0, sizeof(msg));
	iov.iov_base = buf;
	iov.iov_len  = sizeof buf;
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = control;
	msg.msg_controllen = sizeof control;

	do {
		len = recvmsg(wl->sock[0], &msg, 0);
	} while (len < 0 && errno == EINTR);

	if (len < 1)
		return -1;

	message = (void *) buf;
	switch (message->opcode) {
	case WESTON_LAUNCHER_OPEN:
		ret = handle_open(wl, &msg, len);
		break;
	}

	return ret;
}
Example #3
0
static void dispatch(struct pfiled *pfiled, struct io *io)
{
	if (cmdline_verbose) { 
		fprintf(stderr, "io: 0x%p, req: 0x%p, op %u\n",
				(void *)io, (void *)io->req, io->req->op);
	}

	switch (io->req->op) {
		case X_READ:
		case X_WRITE:
			handle_read_write(pfiled, io); break;
		case X_INFO:
			handle_info(pfiled, io); break;
		case X_COPY:
			handle_copy(pfiled, io); break;
		case X_DELETE:
			handle_delete(pfiled, io); break;
		case X_OPEN:
			handle_open(pfiled, io); break;
		case X_CLOSE:
			handle_close(pfiled, io); break;
			//	case X_SNAPSHOT:
		case X_SYNC:
		default:
			handle_unknown(pfiled, io);
	}
}
Example #4
0
extern int mainHeatShrink(const char pCh, const char * const inFName, const char * const outFNamem, const int wSize, const int lSize) {

    size_t sizeStack = 0;
    top_of_stack = (size_t) &sizeStack;

    config cfg;
    memset(&cfg, 0, sizeof(cfg));
    getinputArgs( &cfg, pCh, inFName, outFNamem, wSize, lSize);
    //proc_args(&cfg, argc, argv);

    if (0 == strcmp(cfg.in_fname, cfg.out_fname)
        && (0 != strcmp("-", cfg.in_fname))) {
        fprintf(stderr, "Refusing to overwrite file '%s' with itself.\n", cfg.in_fname);
        exit(1);
    }

    cfg.in = handle_open(cfg.in_fname, IO_READ, cfg.buffer_size);
    if (cfg.in == NULL) { die("Failed to open input file for read"); }
    cfg.out = handle_open(cfg.out_fname, IO_WRITE, cfg.buffer_size);
    if (cfg.out == NULL) { die("Failed to open output file for write"); }

#if _WIN32
    /*
     * On Windows, stdin and stdout default to text mode. Switch them to
     * binary mode before sending data through them.
     */
    _setmode(STDOUT_FILENO, O_BINARY);
    _setmode(STDIN_FILENO, O_BINARY);
#endif

    if (cfg.cmd == OP_ENC) {
        encode(&cfg);
    } else if (cfg.cmd == OP_DEC) {
        decode(&cfg);
    } else {
        usage();
    }
    sizeStack = SizeOfStack();


    return sizeStack;
}
Example #5
0
int main(int argc, char **argv) {
    config cfg;
    memset(&cfg, 0, sizeof(cfg));
    proc_args(&cfg, argc, argv);

    if (0 == strcmp(cfg.in_fname, cfg.out_fname)
        && (0 != strcmp("-", cfg.in_fname))) {
        printf("Refusing to overwrite file '%s' with itself.\n", cfg.in_fname);
        exit(1);
    }

    cfg.in = handle_open(cfg.in_fname, IO_READ, cfg.buffer_size);
    if (cfg.in == NULL) { die("Failed to open input file for read"); }
    cfg.out = handle_open(cfg.out_fname, IO_WRITE, cfg.buffer_size);
    if (cfg.out == NULL) { die("Failed to open output file for write"); }

    if (cfg.cmd == OP_ENC) {
        return encode(&cfg);
    } else if (cfg.cmd == OP_DEC) {
        return decode(&cfg);
    } else {
        usage();
    }
}
Example #6
0
int
handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
{
  if (strncmp (own_buf, "vFile:open:", 11) == 0)
    handle_open (own_buf);
  else if (strncmp (own_buf, "vFile:pread:", 11) == 0)
    handle_pread (own_buf, new_packet_len);
  else if (strncmp (own_buf, "vFile:pwrite:", 12) == 0)
    handle_pwrite (own_buf, packet_len);
  else if (strncmp (own_buf, "vFile:close:", 12) == 0)
    handle_close (own_buf);
  else if (strncmp (own_buf, "vFile:unlink:", 13) == 0)
    handle_unlink (own_buf);
  else
    return 0;

  return 1;
}
Example #7
0
void handle_syscall(syscall_req_t* req, syscall_rsp_t* rsp)
{
	switch (req->header.id) {
		case OPEN_ID:
			handle_open(req, rsp);
			break;
		case CLOSE_ID:
			handle_close(req, rsp);
			break;
		case READ_ID:
			handle_read(req, rsp);
			break;
		case WRITE_ID:
			handle_write(req, rsp);
			break;
		case LINK_ID:
			handle_link(req, rsp);
			break;
		case UNLINK_ID:
			handle_unlink(req, rsp);
			break;
		case LSEEK_ID:
			handle_lseek(req, rsp);
			break;
		case FSTAT_ID:
			handle_fstat(req, rsp);
			break;
		case ISATTY_ID:
			handle_isatty(req, rsp);
			break;
		case STAT_ID:
			handle_stat(req, rsp);
			break;
		default:
			error(-1, "Illegal syscall, should never be here...");
	}
	
	rsp->header.return_errno = errno;
}
Example #8
0
int
handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
{
  if (startswith (own_buf, "vFile:open:"))
    handle_open (own_buf);
  else if (startswith (own_buf, "vFile:pread:"))
    handle_pread (own_buf, new_packet_len);
  else if (startswith (own_buf, "vFile:pwrite:"))
    handle_pwrite (own_buf, packet_len);
  else if (startswith (own_buf, "vFile:fstat:"))
    handle_fstat (own_buf, new_packet_len);
  else if (startswith (own_buf, "vFile:close:"))
    handle_close (own_buf);
  else if (startswith (own_buf, "vFile:unlink:"))
    handle_unlink (own_buf);
  else if (startswith (own_buf, "vFile:readlink:"))
    handle_readlink (own_buf, new_packet_len);
  else
    return 0;

  return 1;
}
Example #9
0
static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_task* task)
{
	struct snapraid_io* io = worker->io;
	struct snapraid_state* state = io->state;
	struct snapraid_handle* handle = worker->handle;
	struct snapraid_disk* disk = handle->disk;
	block_off_t blockcur = task->position;
	unsigned char* buffer = task->buffer;
	int ret;
	char esc_buffer[ESC_MAX];

	/* if the disk position is not used */
	if (!disk) {
		/* use an empty block */
		memset(buffer, 0, state->block_size);
		task->state = TASK_STATE_DONE;
		return;
	}

	/* get the block */
	task->block = fs_par2block_find(disk, blockcur);

	/* if the block is not used */
	if (!block_has_file(task->block)) {
		/* use an empty block */
		memset(buffer, 0, state->block_size);
		task->state = TASK_STATE_DONE;
		return;
	}

	/* get the file of this block */
	task->file = fs_par2file_get(disk, blockcur, &task->file_pos);

	/* if the file is different than the current one, close it */
	if (handle->file != 0 && handle->file != task->file) {
		/* keep a pointer at the file we are going to close for error reporting */
		struct snapraid_file* report = handle->file;
		ret = handle_close(handle);
		if (ret == -1) {
			/* LCOV_EXCL_START */
			/* This one is really an unexpected error, because we are only reading */
			/* and closing a descriptor should never fail */
			if (errno == EIO) {
				log_tag("error:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc(report->sub, esc_buffer), strerror(errno));
				log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to scrub.\n");
				log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path);
				log_fatal("Stopping at block %u\n", blockcur);
				task->state = TASK_STATE_IOERROR;
				return;
			}

			log_tag("error:%u:%s:%s: Close error. %s\n", blockcur, disk->name, esc(report->sub, esc_buffer), strerror(errno));
			log_fatal("WARNING! Unexpected close error in a data disk, it isn't possible to scrub.\n");
			log_fatal("Ensure that file '%s' can be accessed.\n", handle->path);
			log_fatal("Stopping at block %u\n", blockcur);
			task->state = TASK_STATE_ERROR;
			return;
			/* LCOV_EXCL_STOP */
		}
	}

	ret = handle_open(handle, task->file, state->file_mode, log_error, 0);
	if (ret == -1) {
		if (errno == EIO) {
			/* LCOV_EXCL_START */
			log_tag("error:%u:%s:%s: Open EIO error. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), strerror(errno));
			log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to scrub.\n");
			log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path);
			log_fatal("Stopping at block %u\n", blockcur);
			task->state = TASK_STATE_IOERROR;
			return;
			/* LCOV_EXCL_STOP */
		}

		log_tag("error:%u:%s:%s: Open error. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), strerror(errno));
		task->state = TASK_STATE_ERROR_CONTINUE;
		return;
	}

	/* check if the file is changed */
	if (handle->st.st_size != task->file->size
		|| handle->st.st_mtime != task->file->mtime_sec
		|| STAT_NSEC(&handle->st) != task->file->mtime_nsec
		/* don't check the inode to support filesystem without persistent inodes */
	) {
		/* report that the block and the file are not synced */
		task->is_timestamp_different = 1;
		/* follow */
	}

	/* note that we intentionally don't abort if the file has different attributes */
	/* from the last sync, as we are expected to return errors if running */
	/* in an unsynced array. This is just like the check command. */

	task->read_size = handle_read(handle, task->file_pos, buffer, state->block_size, log_error, 0);
	if (task->read_size == -1) {
		if (errno == EIO) {
			log_tag("error:%u:%s:%s: Read EIO error at position %u. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), task->file_pos, strerror(errno));
			log_error("Input/Output error in file '%s' at position '%u'\n", handle->path, task->file_pos);
			task->state = TASK_STATE_IOERROR_CONTINUE;
			return;
		}

		log_tag("error:%u:%s:%s: Read error at position %u. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), task->file_pos, strerror(errno));
		task->state = TASK_STATE_ERROR_CONTINUE;
		return;
	}

	/* store the path of the opened file */
	pathcpy(task->path, sizeof(task->path), handle->path);

	task->state = TASK_STATE_DONE;
}
Example #10
0
static void dry_data_reader(struct snapraid_worker* worker, struct snapraid_task* task)
{
	struct snapraid_io* io = worker->io;
	struct snapraid_state* state = io->state;
	struct snapraid_handle* handle = worker->handle;
	struct snapraid_disk* disk = handle->disk;
	block_off_t blockcur = task->position;
	unsigned char* buffer = task->buffer;
	int ret;
	char esc_buffer[ESC_MAX];

	/* if the disk position is not used */
	if (!disk) {
		/* use an empty block */
		memset(buffer, 0, state->block_size);
		task->state = TASK_STATE_DONE;
		return;
	}

	/* get the block */
	task->block = fs_par2block_find(disk, blockcur);

	/* if the block is not used */
	if (!block_has_file(task->block)) {
		/* use an empty block */
		memset(buffer, 0, state->block_size);
		task->state = TASK_STATE_DONE;
		return;
	}

	/* get the file of this block */
	task->file = fs_par2file_get(disk, blockcur, &task->file_pos);

	/* if the file is different than the current one, close it */
	if (handle->file != 0 && handle->file != task->file) {
		/* keep a pointer at the file we are going to close for error reporting */
		struct snapraid_file* report = handle->file;
		ret = handle_close(handle);
		if (ret == -1) {
			/* LCOV_EXCL_START */
			/* This one is really an unexpected error, because we are only reading */
			/* and closing a descriptor should never fail */
			if (errno == EIO) {
				log_tag("error:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc(report->sub, esc_buffer), strerror(errno));
				log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to dry.\n");
				log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path);
				log_fatal("Stopping at block %u\n", blockcur);
				task->state = TASK_STATE_IOERROR;
				return;
			}

			log_tag("error:%u:%s:%s: Close error. %s\n", blockcur, disk->name, esc(report->sub, esc_buffer), strerror(errno));
			log_fatal("WARNING! Unexpected close error in a data disk, it isn't possible to dry.\n");
			log_fatal("Ensure that file '%s' can be accessed.\n", handle->path);
			log_fatal("Stopping at block %u\n", blockcur);
			task->state = TASK_STATE_ERROR;
			return;
			/* LCOV_EXCL_STOP */
		}
	}

	ret = handle_open(handle, task->file, state->file_mode, log_error, 0);
	if (ret == -1) {
		if (errno == EIO) {
			/* LCOV_EXCL_START */
			log_tag("error:%u:%s:%s: Open EIO error. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), strerror(errno));
			log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to dry.\n");
			log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path);
			log_fatal("Stopping at block %u\n", blockcur);
			task->state = TASK_STATE_IOERROR;
			return;
			/* LCOV_EXCL_STOP */
		}

		log_tag("error:%u:%s:%s: Open error. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), strerror(errno));
		task->state = TASK_STATE_ERROR_CONTINUE;
		return;
	}

	task->read_size = handle_read(handle, task->file_pos, buffer, state->block_size, log_error, 0);
	if (task->read_size == -1) {
		if (errno == EIO) {
			log_tag("error:%u:%s:%s: Read EIO error at position %u. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), task->file_pos, strerror(errno));
			log_error("Input/Output error in file '%s' at position '%u'\n", handle->path, task->file_pos);
			task->state = TASK_STATE_IOERROR_CONTINUE;
			return;
		}

		log_tag("error:%u:%s:%s: Read error at position %u. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), task->file_pos, strerror(errno));
		task->state = TASK_STATE_ERROR_CONTINUE;
		return;
	}

	/* store the path of the opened file */
	pathcpy(task->path, sizeof(task->path), handle->path);

	task->state = TASK_STATE_DONE;
}
Example #11
0
static int state_scrub_process(struct snapraid_state* state, struct snapraid_parity** parity, block_off_t blockstart, block_off_t blockmax, time_t timelimit, block_off_t countlimit, time_t now)
{
	struct snapraid_handle* handle;
	void* rehandle_alloc;
	struct snapraid_rehash* rehandle;
	unsigned diskmax;
	block_off_t i;
	unsigned j;
	void* buffer_alloc;
	void** buffer;
	unsigned buffermax;
	data_off_t countsize;
	block_off_t countpos;
	block_off_t countmax;
	block_off_t recountmax;
	block_off_t autosavedone;
	block_off_t autosavelimit;
	block_off_t autosavemissing;
	int ret;
	unsigned error;
	unsigned silent_error;
	unsigned l;

	/* maps the disks to handles */
	handle = handle_map(state, &diskmax);

	/* rehash buffers */
	rehandle = malloc_nofail_align(diskmax * sizeof(struct snapraid_rehash), &rehandle_alloc);

	/* we need disk + 2 for each parity level buffers */
	buffermax = diskmax + state->level * 2;

	buffer = malloc_nofail_vector_align(diskmax, buffermax, state->block_size, &buffer_alloc);
	if (!state->opt.skip_self)
		mtest_vector(buffermax, state->block_size, buffer);

	error = 0;
	silent_error = 0;

	/* first count the number of blocks to process */
	countmax = 0;
	for(i=blockstart;i<blockmax;++i) {
		time_t blocktime;
		snapraid_info info;

		/* if it's unused */
		info = info_get(&state->infoarr, i);
		if (info == 0) {
			/* skip it */
			continue;
		}

		/* blocks marked as bad are always checked */
		if (!info_get_bad(info)) {

			/* if it's too new */
			blocktime = info_get_time(info);
			if (blocktime > timelimit) {
				/* skip it */
				continue;
			}

			/* skip odd blocks, used only for testing */
			if (state->opt.force_scrub_even && (i % 2) != 0) {
				/* skip it */
				continue;
			}

			/* if the time is less than the limit, always include */
			/* otherwise, check if we reached the max count */
			if (blocktime == timelimit) {
				/* if we reached the count limit */
				if (countmax >= countlimit) {
					/* skip it */
					continue;
				}
			}
		}

		++countmax;
	}

	/* compute the autosave size for all disk, even if not read */
	/* this makes sense because the speed should be almost the same */
	/* if the disks are read in parallel */
	autosavelimit = state->autosave / (diskmax * state->block_size);
	autosavemissing = countmax; /* blocks to do */
	autosavedone = 0; /* blocks done */

	countsize = 0;
	countpos = 0;
	state_progress_begin(state, blockstart, blockmax, countmax);
	recountmax = 0;
	for(i=blockstart;i<blockmax;++i) {
		time_t blocktime;
		snapraid_info info;
		int error_on_this_block;
		int silent_error_on_this_block;
		int block_is_unsynced;
		int rehash;

		/* if it's unused */
		info = info_get(&state->infoarr, i);
		if (info == 0) {
			/* skip it */
			continue;
		}

		/* blocks marked as bad are always checked */
		if (!info_get_bad(info)) {

			/* if it's too new */
			blocktime = info_get_time(info);
			if (blocktime > timelimit) {
				/* skip it */
				continue;
			}

			/* skip odd blocks, used only for testing */
			if (state->opt.force_scrub_even && (i % 2) != 0) {
				/* skip it */
				continue;
			}

			/* if the time is less than the limit, always include */
			/* otherwise, check if we reaced the count max */
			if (blocktime == timelimit) {
				/* if we reached the count limit */
				if (recountmax >= countlimit) {
					/* skip it */
					continue;
				}
			}
		}

		++recountmax;

		/* one more block processed for autosave */
		++autosavedone;
		--autosavemissing;

		/* by default process the block, and skip it if something goes wrong */
		error_on_this_block = 0;
		silent_error_on_this_block = 0;

		/* if all the blocks at this address are synced */
		/* if not, parity is not even checked */
		block_is_unsynced = 0;

		/* if we have to use the old hash */
		rehash = info_get_rehash(info);

		/* for each disk, process the block */
		for(j=0;j<diskmax;++j) {
			int read_size;
			unsigned char hash[HASH_SIZE];
			struct snapraid_block* block;
			int file_is_unsynced;

			/* if the file on this disk is synced */
			/* if not, silent errors are assumed as expected error */
			file_is_unsynced = 0;

			/* by default no rehash in case of "continue" */
			rehandle[j].block = 0;

			/* if the disk position is not used */
			if (!handle[j].disk) {
				/* use an empty block */
				memset(buffer[j], 0, state->block_size);
				continue;
			}

			/* if the block is not used */
			block = disk_block_get(handle[j].disk, i);
			if (!block_has_file(block)) {
				/* use an empty block */
				memset(buffer[j], 0, state->block_size);
				continue;
			}

			/* if the block is unsynced, errors are expected */
			if (block_has_invalid_parity(block)) {
				/* report that the block and the file are not synced */
				block_is_unsynced = 1;
				file_is_unsynced = 1;

				/* follow */
			}

			/* if the file is different than the current one, close it */
			if (handle[j].file != 0 && handle[j].file != block_file_get(block)) {
				/* keep a pointer at the file we are going to close for error reporting */
				struct snapraid_file* file = handle[j].file;
				ret = handle_close(&handle[j]);
				if (ret == -1) {
					/* LCOV_EXCL_START */
					/* This one is really an unexpected error, because we are only reading */
					/* and closing a descriptor should never fail */
					fprintf(stdlog, "error:%u:%s:%s: Close error. %s\n", i, handle[j].disk->name, file->sub, strerror(errno));
					fprintf(stderr, "DANGER! Unexpected close error in a data disk, it isn't possible to scrub.\n");
					printf("Stopping at block %u\n", i);
					++error;
					goto bail;
					/* LCOV_EXCL_STOP */
				}
			}

			ret = handle_open(&handle[j], block_file_get(block), state->opt.skip_sequential, stderr);
			if (ret == -1) {
				/* file we have tried to open for error reporting */
				struct snapraid_file* file = block_file_get(block);
				fprintf(stdlog, "error:%u:%s:%s: Open error. %s\n", i, handle[j].disk->name, file->sub, strerror(errno));
				++error;
				error_on_this_block = 1;
				continue;
			}

			/* check if the file is changed */
			if (handle[j].st.st_size != block_file_get(block)->size
				|| handle[j].st.st_mtime != block_file_get(block)->mtime_sec
				|| STAT_NSEC(&handle[j].st) != block_file_get(block)->mtime_nsec
				|| handle[j].st.st_ino != block_file_get(block)->inode
			) {
				/* report that the block and the file are not synced */
				block_is_unsynced = 1;
				file_is_unsynced = 1;

				/* follow */
			}

			/* note that we intentionally don't abort if the file has different attributes */
			/* from the last sync, as we are expected to return errors if running */
			/* in an unsynced array. This is just like the check command. */

			read_size = handle_read(&handle[j], block, buffer[j], state->block_size, stderr);
			if (read_size == -1) {
				fprintf(stdlog, "error:%u:%s:%s: Read error at position %u\n", i, handle[j].disk->name, handle[j].file->sub, block_file_pos(block));
				++error;
				error_on_this_block = 1;
				continue;
			}

			countsize += read_size;

			/* now compute the hash */
			if (rehash) {
				memhash(state->prevhash, state->prevhashseed, hash, buffer[j], read_size);

				/* compute the new hash, and store it */
				rehandle[j].block = block;
				memhash(state->hash, state->hashseed, rehandle[j].hash, buffer[j], read_size);
			} else {
				memhash(state->hash, state->hashseed, hash, buffer[j], read_size);
			}

			if (block_has_updated_hash(block)) {
				/* compare the hash */
				if (memcmp(hash, block->hash, HASH_SIZE) != 0) {
					fprintf(stdlog, "error:%u:%s:%s: Data error at position %u\n", i, handle[j].disk->name, handle[j].file->sub, block_file_pos(block));

					/* it's a silent error only if we are dealing with synced files */
					if (file_is_unsynced) {
						++error;
						error_on_this_block = 1;
					} else {
						fprintf(stderr, "Data error in file '%s' at position '%u'\n", handle[j].path, block_file_pos(block));
						fprintf(stderr, "WARNING! Unexpected data error in a data disk! The block is now marked as bad!\n");
						fprintf(stderr, "Try with 'snapraid -e fix' to recover!\n");

						++silent_error;
						silent_error_on_this_block = 1;
					}
					continue;
				}
			}
		}

		/* if we have read all the data required and it's correct, proceed with the parity check */
		if (!error_on_this_block && !silent_error_on_this_block) {
			unsigned char* buffer_recov[LEV_MAX];

			/* buffers for parity read and not computed */
			for(l=0;l<state->level;++l)
				buffer_recov[l] = buffer[diskmax + state->level + l];
			for(;l<LEV_MAX;++l)
				buffer_recov[l] = 0;

			/* read the parity */
			for(l=0;l<state->level;++l) {
				ret = parity_read(parity[l], i, buffer_recov[l], state->block_size, stdlog);
				if (ret == -1) {
					buffer_recov[l] = 0;
					fprintf(stdlog, "parity_error:%u:%s: Read error\n", i, lev_config_name(l));
					++error;
					error_on_this_block = 1;

					/* follow */
				}
			}

			/* compute the parity */
			raid_gen(diskmax, state->level, state->block_size, buffer);

			/* compare the parity */
			for(l=0;l<state->level;++l) {
				if (buffer_recov[l] && memcmp(buffer[diskmax + l], buffer_recov[l], state->block_size) != 0) {
					fprintf(stdlog, "parity_error:%u:%s: Data error\n", i, lev_config_name(l));

					/* it's a silent error only if we are dealing with synced blocks */
					if (block_is_unsynced) {
						++error;
						error_on_this_block = 1;
					} else {
						fprintf(stderr, "Data error in parity '%s' at position '%u'\n", lev_config_name(l), i);
						fprintf(stderr, "WARNING! Unexpected data error in a parity disk! The block is now marked as bad!\n");
						fprintf(stderr, "Try with 'snapraid -e fix' to recover!\n");

						++silent_error;
						silent_error_on_this_block = 1;
					}
				}
			}
		}

		if (silent_error_on_this_block) {
			/* set the error status keeping the existing time and hash */
			info_set(&state->infoarr, i, info_set_bad(info));
		} else if (error_on_this_block) {
			/* do nothing, as this is a generic error */
			/* likely caused by a not synced array */
		} else {
			/* if rehash is needed */
			if (rehash) {
				/* store all the new hash already computed */
				for(j=0;j<diskmax;++j) {
					if (rehandle[j].block)
						memcpy(rehandle[j].block->hash, rehandle[j].hash, HASH_SIZE);
				}
			}

			/* update the time info of the block */
			/* and clear any other flag */
			info_set(&state->infoarr, i, info_make(now, 0, 0));
		}

		/* mark the state as needing write */
		state->need_write = 1;

		/* count the number of processed block */
		++countpos;

		/* progress */
		if (state_progress(state, i, countpos, countmax, countsize)) {
			/* LCOV_EXCL_START */
			break;
			/* LCOV_EXCL_STOP */
		}

		/* autosave */
		if (state->autosave != 0
			&& autosavedone >= autosavelimit /* if we have reached the limit */
			&& autosavemissing >= autosavelimit /* if we have at least a full step to do */
		) {
			autosavedone = 0; /* restart the counter */

			state_progress_stop(state);

			printf("Autosaving...\n");
			state_write(state);

			state_progress_restart(state);
		}
	}

	state_progress_end(state, countpos, countmax, countsize);

	if (error || silent_error) {
		printf("\n");
		printf("%8u read errors\n", error);
		printf("%8u data errors\n", silent_error);
		printf("WARNING! There are errors!\n");
	} else {
		/* print the result only if processed something */
		if (countpos != 0)
			printf("Everything OK\n");
	}

	fprintf(stdlog, "summary:error_read:%u\n", error);
	fprintf(stdlog, "summary:error_data:%u\n", silent_error);
	if (error + silent_error == 0)
		fprintf(stdlog, "summary:exit:ok\n");
	else
		fprintf(stdlog, "summary:exit:error\n");
	fflush(stdlog);

bail:
	for(j=0;j<diskmax;++j) {
		ret = handle_close(&handle[j]);
		if (ret == -1) {
			/* LCOV_EXCL_START */
			fprintf(stderr, "DANGER! Unexpected close error in a data disk.\n");
			++error;
			/* continue, as we are already exiting */
			/* LCOV_EXCL_STOP */
		}
	}

	free(handle);
	free(buffer_alloc);
	free(buffer);
	free(rehandle_alloc);

	if (state->opt.expect_recoverable) {
		if (error + silent_error == 0)
			return -1;
	} else {
		if (error + silent_error != 0)
			return -1;
	}
	return 0;
}
Example #12
0
void do_menu_command(
	long menuResult) 
{
	short menuID;
	short menuItem;

	menuID= GET_MENU_ID(menuResult);
	menuItem= GET_MENU_ITEM(menuResult);
	
	switch (menuID) 
	{
		case mApple:
			switch (menuItem) 
			{
				case iAbout:
					break;
				default:
#if defined(OP_PLATFORM_MAC_CFM) && !defined(OP_PLATFORM_MAC_CARBON_FLAG)
					{
						Str255 daName;
						
						GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
						OpenDeskAcc(daName);
					}
#endif
					break;
			}
			break;

		case mFile:
			switch (menuItem) 
			{
				case iOpen:
				case iOpenPassive:
					handle_open(menuItem==iOpen, false);
					break;
					
				case iOpenActiveUI:
				case iOpenPassiveUI:
					handle_open(menuItem==iOpenActiveUI, true);
					break;
					
				case iClose:
					close_front_window();
					break;
					
				case iQuit:
					handle_quit();
					break;
			}
			break;
			
		case mSpecial:
			switch(menuItem)
			{
				case iSendPacket:
					send_packet();
					break;
				
				case iSendStream:
					send_stream();
					break;
					
				case iProtocolAlive:
					is_alive();
					break;
					
				case iAcceptingConnections:
					accepting_connections= !accepting_connections;
					check_menu_item(menuID, menuItem, accepting_connections);
					break;

				case iActiveEnumeration:
					active_enumeration= !active_enumeration;
					check_menu_item(menuID, menuItem, active_enumeration);
					break;
					
				case iSetTimeout:
					set_timeout();
					break;
					
				case iGetInfo:
					report_info();
					break;
					
				case iGetConfigString:
//					get_config_string();
					break;
			}
			break;
			
		case mWindowMenu:
			switch(menuItem)
			{
				case iCascade:
				case iTile:
					cascade_or_tile_windows(menuItem==iCascade);
					break;
			}
	}
#if OP_PLATFORM_MAC_CFM || OP_PLATFORM_MAC_MACHO
	HiliteMenu(0);
#endif
	adjust_menus();

	return;
}
Example #13
0
File: dry.c Project: GDXN/snapraid
static int state_dry_process(struct snapraid_state* state, struct snapraid_parity** parity, block_off_t blockstart, block_off_t blockmax)
{
	struct snapraid_handle* handle;
	unsigned diskmax;
	block_off_t i;
	unsigned j;
	void* buffer_alloc;
	unsigned char* buffer_aligned;
	int ret;
	data_off_t countsize;
	block_off_t countpos;
	block_off_t countmax;
	unsigned error;
	unsigned l;

	handle = handle_map(state, &diskmax);

	buffer_aligned = malloc_nofail_align(state->block_size, &buffer_alloc);

	error = 0;

	/* dry all the blocks in files */
	countmax = blockmax - blockstart;
	countsize = 0;
	countpos = 0;
	state_progress_begin(state, blockstart, blockmax, countmax);
	for(i=blockstart;i<blockmax;++i) {
		/* for each disk, process the block */
		for(j=0;j<diskmax;++j) {
			int read_size;
			struct snapraid_block* block = BLOCK_EMPTY;

			if (handle[j].disk)
				block = disk_block_get(handle[j].disk, i);

			if (!block_has_file(block)) {
				/* if no file, nothing to do */
				continue;
			}

			/* if the file is closed or different than the current one */
			if (handle[j].file == 0 || handle[j].file != block_file_get(block)) {
				/* close the old one, if any */
				ret = handle_close(&handle[j]);
				if (ret == -1) {
					/* LCOV_EXCL_START */
					fprintf(stderr, "DANGER! Unexpected close error in a data disk, it isn't possible to dry.\n");
					printf("Stopping at block %u\n", i);
					++error;
					goto bail;
					/* LCOV_EXCL_STOP */
				}

				/* open the file only for reading */
				ret = handle_open(&handle[j], block_file_get(block), state->opt.skip_sequential, stdlog);
				if (ret == -1) {
					/* LCOV_EXCL_START */
					fprintf(stderr, "DANGER! Unexpected open error in a data disk, it isn't possible to dry.\n");
					printf("Stopping at block %u\n", i);
					++error;
					goto bail;
					/* LCOV_EXCL_STOP */
				}
			}

			/* read from the file */
			read_size = handle_read(&handle[j], block, buffer_aligned, state->block_size, stdlog);
			if (read_size == -1) {
				fprintf(stdlog, "error:%u:%s:%s: Read error at position %u\n", i, handle[j].disk->name, block_file_get(block)->sub, block_file_pos(block));
				++error;
				continue;
			}

			countsize += read_size;
		}

		/* read the parity */
		for(l=0;l<state->level;++l) {
			if (parity[l]) {
				ret = parity_read(parity[l], i, buffer_aligned, state->block_size, stdlog);
				if (ret == -1) {
					fprintf(stdlog, "parity_error:%u:%s: Read error\n", i, lev_config_name(l));
					++error;
				}
			}
		}

		/* count the number of processed block */
		++countpos;

		/* progress */
		if (state_progress(state, i, countpos, countmax, countsize)) {
			/* LCOV_EXCL_START */
			break;
			/* LCOV_EXCL_STOP */
		}
	}

	state_progress_end(state, countpos, countmax, countsize);

bail:
	/* close all the files left open */
	for(j=0;j<diskmax;++j) {
		ret = handle_close(&handle[j]);
		if (ret == -1) {
			/* LCOV_EXCL_START */
			fprintf(stderr, "DANGER! Unexpected close error in a data disk.\n");
			++error;
			/* continue, as we are already exiting */
			/* LCOV_EXCL_STOP */
		}
	}

	if (error) {
		printf("%u read errors\n", error);
	} else {
		printf("Everything OK\n");
	}

	free(handle);
	free(buffer_alloc);

	if (error != 0)
		return -1;
	return 0;
}
int run_fuse_sideload(struct provider_vtab* vtab, void* cookie,
                      uint64_t file_size, uint32_t block_size)
{
    int result;
    uint64_t mem = 0;
    uint64_t avail = 0;

    // If something's already mounted on our mountpoint, try to remove
    // it.  (Mostly in case of a previous abnormal exit.)
    umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_FORCE);

    if (block_size < 1024) {
        fprintf(stderr, "block size (%u) is too small\n", block_size);
        return -1;
    }
    if (block_size > (1<<22)) {   // 4 MiB
        fprintf(stderr, "block size (%u) is too large\n", block_size);
        return -1;
    }

    struct fuse_data fd;
    memset(&fd, 0, sizeof(fd));
    fd.vtab = vtab;
    fd.cookie = cookie;
    fd.file_size = file_size;
    fd.block_size = block_size;
    fd.file_blocks = (file_size == 0) ? 0 : (((file_size-1) / block_size) + 1);

    if (fd.file_blocks > (1<<18)) {
        fprintf(stderr, "file has too many blocks (%u)\n", fd.file_blocks);
        result = -1;
        goto done;
    }

    fd.hashes = (uint8_t*)calloc(fd.file_blocks, SHA256_DIGEST_SIZE);
    if (fd.hashes == NULL) {
        fprintf(stderr, "failed to allocate %d bites for hashes\n",
                fd.file_blocks * SHA256_DIGEST_SIZE);
        result = -1;
        goto done;
    }

    fd.uid = getuid();
    fd.gid = getgid();

    fd.curr_block = -1;
    fd.block_data = (uint8_t*)malloc(block_size);
    if (fd.block_data == NULL) {
        fprintf(stderr, "failed to allocate %d bites for block_data\n", block_size);
        result = -1;
        goto done;
    }
    fd.extra_block = (uint8_t*)malloc(block_size);
    if (fd.extra_block == NULL) {
        fprintf(stderr, "failed to allocate %d bites for extra_block\n", block_size);
        result = -1;
        goto done;
    }

    fd.block_cache_max_size = 0;
    fd.block_cache_size = 0;
    fd.block_cache = NULL;
    mem = free_memory();
    avail = mem - (INSTALL_REQUIRED_MEMORY + fd.file_blocks * sizeof(uint8_t*));
    if (mem > avail) {
        uint32_t max_size = avail / fd.block_size;
        if (max_size > fd.file_blocks) {
            max_size = fd.file_blocks;
        }
        // The cache must be at least 1% of the file size or two blocks,
        // whichever is larger.
        if (max_size >= fd.file_blocks/100 && max_size >= 2) {
            fd.block_cache_max_size = max_size;
            fd.block_cache = (uint8_t**)calloc(fd.file_blocks, sizeof(uint8_t*));
        }
    }

    signal(SIGTERM, sig_term);

    fd.ffd = open("/dev/fuse", O_RDWR);
    if (fd.ffd < 0) {
        perror("open /dev/fuse");
        result = -1;
        goto done;
    }

    char opts[256];
    snprintf(opts, sizeof(opts),
             ("fd=%d,user_id=%d,group_id=%d,max_read=%u,"
              "allow_other,rootmode=040000"),
             fd.ffd, fd.uid, fd.gid, block_size);

    result = mount("/dev/fuse", FUSE_SIDELOAD_HOST_MOUNTPOINT,
                   "fuse", MS_NOSUID | MS_NODEV | MS_RDONLY | MS_NOEXEC, opts);
    if (result < 0) {
        perror("mount");
        goto done;
    }
    uint8_t request_buffer[sizeof(struct fuse_in_header) + PATH_MAX*8];
    while (!terminated) {
        fd_set fds;
        struct timeval tv;
        FD_ZERO(&fds);
        FD_SET(fd.ffd, &fds);
        tv.tv_sec = 1;
        tv.tv_usec = 0;
        int rc = select(fd.ffd+1, &fds, NULL, NULL, &tv);
        if (rc <= 0) {
            continue;
        }
        ssize_t len = TEMP_FAILURE_RETRY(read(fd.ffd, request_buffer, sizeof(request_buffer)));
        if (len < 0) {
            if (errno != EINTR) {
                perror("read request");
                if (errno == ENODEV) {
                    result = -1;
                    break;
                }
            }
            continue;
        }

        if ((size_t)len < sizeof(struct fuse_in_header)) {
            fprintf(stderr, "request too short: len=%zu\n", (size_t)len);
            continue;
        }

        struct fuse_in_header* hdr = (struct fuse_in_header*) request_buffer;
        void* data = request_buffer + sizeof(struct fuse_in_header);

        result = -ENOSYS;

        switch (hdr->opcode) {
             case FUSE_INIT:
                result = handle_init(data, &fd, hdr);
                break;

             case FUSE_LOOKUP:
                result = handle_lookup(data, &fd, hdr);
                break;

            case FUSE_GETATTR:
                result = handle_getattr(data, &fd, hdr);
                break;

            case FUSE_OPEN:
                result = handle_open(data, &fd, hdr);
                break;

            case FUSE_READ:
                result = handle_read(data, &fd, hdr);
                break;

            case FUSE_FLUSH:
                result = handle_flush(data, &fd, hdr);
                break;

            case FUSE_RELEASE:
                result = handle_release(data, &fd, hdr);
                break;

            default:
                fprintf(stderr, "unknown fuse request opcode %d\n", hdr->opcode);
                break;
        }

        if (result != NO_STATUS) {
            struct fuse_out_header outhdr;
            outhdr.len = sizeof(outhdr);
            outhdr.error = result;
            outhdr.unique = hdr->unique;
            TEMP_FAILURE_RETRY(write(fd.ffd, &outhdr, sizeof(outhdr)));
        }
    }

  done:
    fd.vtab->close(fd.cookie);

    result = umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_DETACH);
    if (result < 0) {
        printf("fuse_sideload umount failed: %s\n", strerror(errno));
    }

    if (fd.ffd) close(fd.ffd);
    if (fd.block_cache) {
        uint32_t n;
        for (n = 0; n < fd.file_blocks; ++n) {
            free(fd.block_cache[n]);
        }
        free(fd.block_cache);
    }
    free(fd.hashes);
    free(fd.block_data);
    free(fd.extra_block);

    return result;
}
Example #15
0
int run_fuse_sideload(struct provider_vtab* vtab, void* cookie,
                      uint64_t file_size, uint32_t block_size)
{
    int result;

    // If something's already mounted on our mountpoint, try to remove
    // it.  (Mostly in case of a previous abnormal exit.)
    umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_FORCE);

    if (block_size < 1024) {
        fprintf(stderr, "block size (%u) is too small\n", block_size);
        return -1;
    }
    if (block_size > (1<<22)) {   // 4 MiB
        fprintf(stderr, "block size (%u) is too large\n", block_size);
        return -1;
    }

    struct fuse_data fd;
    memset(&fd, 0, sizeof(fd));
    fd.vtab = vtab;
    fd.cookie = cookie;
    fd.file_size = file_size;
    fd.block_size = block_size;
    fd.file_blocks = (file_size == 0) ? 0 : (((file_size-1) / block_size) + 1);

    if (fd.file_blocks > (1<<18)) {
        fprintf(stderr, "file has too many blocks (%u)\n", fd.file_blocks);
        result = -1;
        goto done;
    }

    fd.hashes = (uint8_t*)calloc(fd.file_blocks, SHA256_DIGEST_SIZE);
    if (fd.hashes == NULL) {
        fprintf(stderr, "failed to allocate %d bites for hashes\n",
                fd.file_blocks * SHA256_DIGEST_SIZE);
        result = -1;
        goto done;
    }

    fd.uid = getuid();
    fd.gid = getgid();

    fd.curr_block = -1;
    fd.block_data = (uint8_t*)malloc(block_size);
    if (fd.block_data == NULL) {
        fprintf(stderr, "failed to allocate %d bites for block_data\n", block_size);
        result = -1;
        goto done;
    }
    fd.extra_block = (uint8_t*)malloc(block_size);
    if (fd.extra_block == NULL) {
        fprintf(stderr, "failed to allocate %d bites for extra_block\n", block_size);
        result = -1;
        goto done;
    }

    fd.ffd = open("/dev/fuse", O_RDWR);
    if (fd.ffd < 0) {
        perror("open /dev/fuse");
        result = -1;
        goto done;
    }

    char opts[256];
    snprintf(opts, sizeof(opts),
             ("fd=%d,user_id=%d,group_id=%d,max_read=%zu,"
              "allow_other,rootmode=040000"),
             fd.ffd, fd.uid, fd.gid, block_size);

    result = mount("/dev/fuse", FUSE_SIDELOAD_HOST_MOUNTPOINT,
                   "fuse", MS_NOSUID | MS_NODEV | MS_RDONLY | MS_NOEXEC, opts);
    if (result < 0) {
        perror("mount");
        goto done;
    }
    uint8_t request_buffer[sizeof(struct fuse_in_header) + PATH_MAX*8];
    for (;;) {
        ssize_t len = read(fd.ffd, request_buffer, sizeof(request_buffer));
        if (len < 0) {
            if (errno != EINTR) {
                perror("read request");
                if (errno == ENODEV) {
                    result = -1;
                    break;
                }
            }
            continue;
        }

        if ((size_t)len < sizeof(struct fuse_in_header)) {
            fprintf(stderr, "request too short: len=%zu\n", (size_t)len);
            continue;
        }

        struct fuse_in_header* hdr = (struct fuse_in_header*) request_buffer;
        void* data = request_buffer + sizeof(struct fuse_in_header);

        result = -ENOSYS;

        switch (hdr->opcode) {
             case FUSE_INIT:
                result = handle_init(data, &fd, hdr);
                break;

             case FUSE_LOOKUP:
                result = handle_lookup(data, &fd, hdr);
                break;

            case FUSE_GETATTR:
                result = handle_getattr(data, &fd, hdr);
                break;

            case FUSE_OPEN:
                result = handle_open(data, &fd, hdr);
                break;

            case FUSE_READ:
                result = handle_read(data, &fd, hdr);
                break;

            case FUSE_FLUSH:
                result = handle_flush(data, &fd, hdr);
                break;

            case FUSE_RELEASE:
                result = handle_release(data, &fd, hdr);
                break;

            default:
                fprintf(stderr, "unknown fuse request opcode %d\n", hdr->opcode);
                break;
        }

        if (result == NO_STATUS_EXIT) {
            result = 0;
            break;
        }

        if (result != NO_STATUS) {
            struct fuse_out_header outhdr;
            outhdr.len = sizeof(outhdr);
            outhdr.error = result;
            outhdr.unique = hdr->unique;
            write(fd.ffd, &outhdr, sizeof(outhdr));
        }
    }

  done:
    fd.vtab->close(fd.cookie);

    result = umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_DETACH);
    if (result < 0) {
        printf("fuse_sideload umount failed: %s\n", strerror(errno));
    }

    if (fd.ffd) close(fd.ffd);
    free(fd.hashes);
    free(fd.block_data);
    free(fd.extra_block);

    return result;
}
Example #16
0
static int state_scrub_process(struct snapraid_state* state, struct snapraid_parity_handle** parity, block_off_t blockstart, block_off_t blockmax, struct snapraid_plan* plan, time_t now)
{
	struct snapraid_handle* handle;
	void* rehandle_alloc;
	struct snapraid_rehash* rehandle;
	unsigned diskmax;
	block_off_t i;
	unsigned j;
	void* buffer_alloc;
	void** buffer;
	unsigned buffermax;
	data_off_t countsize;
	block_off_t countpos;
	block_off_t countmax;
	block_off_t autosavedone;
	block_off_t autosavelimit;
	block_off_t autosavemissing;
	int ret;
	unsigned error;
	unsigned silent_error;
	unsigned io_error;
	unsigned l;

	/* maps the disks to handles */
	handle = handle_map(state, &diskmax);

	/* rehash buffers */
	rehandle = malloc_nofail_align(diskmax * sizeof(struct snapraid_rehash), &rehandle_alloc);

	/* we need disk + 2 for each parity level buffers */
	buffermax = diskmax + state->level * 2;

	buffer = malloc_nofail_vector_align(diskmax, buffermax, state->block_size, &buffer_alloc);
	if (!state->opt.skip_self)
		mtest_vector(buffermax, state->block_size, buffer);

	error = 0;
	silent_error = 0;
	io_error = 0;

	/* first count the number of blocks to process */
	countmax = 0;
	plan->countlast = 0;
	for (i = blockstart; i < blockmax; ++i) {
		if (!block_is_enabled(state, i, plan))
			continue;

		++countmax;
	}

	/* compute the autosave size for all disk, even if not read */
	/* this makes sense because the speed should be almost the same */
	/* if the disks are read in parallel */
	autosavelimit = state->autosave / (diskmax * state->block_size);
	autosavemissing = countmax; /* blocks to do */
	autosavedone = 0; /* blocks done */

	/* drop until now */
	state_usage_waste(state);

	countsize = 0;
	countpos = 0;
	plan->countlast = 0;
	state_progress_begin(state, blockstart, blockmax, countmax);
	for (i = blockstart; i < blockmax; ++i) {
		snapraid_info info;
		int error_on_this_block;
		int silent_error_on_this_block;
		int io_error_on_this_block;
		int block_is_unsynced;
		int rehash;

		if (!block_is_enabled(state, i, plan))
			continue;

		/* one more block processed for autosave */
		++autosavedone;
		--autosavemissing;

		/* by default process the block, and skip it if something goes wrong */
		error_on_this_block = 0;
		silent_error_on_this_block = 0;
		io_error_on_this_block = 0;

		/* if all the blocks at this address are synced */
		/* if not, parity is not even checked */
		block_is_unsynced = 0;

		/* get block specific info */
		info = info_get(&state->infoarr, i);

		/* if we have to use the old hash */
		rehash = info_get_rehash(info);

		/* for each disk, process the block */
		for (j = 0; j < diskmax; ++j) {
			int read_size;
			unsigned char hash[HASH_SIZE];
			struct snapraid_block* block;
			int file_is_unsynced;
			struct snapraid_disk* disk = handle[j].disk;
			struct snapraid_file* file;
			block_off_t file_pos;

			/* if the file on this disk is synced */
			/* if not, silent errors are assumed as expected error */
			file_is_unsynced = 0;

			/* by default no rehash in case of "continue" */
			rehandle[j].block = 0;

			/* if the disk position is not used */
			if (!disk) {
				/* use an empty block */
				memset(buffer[j], 0, state->block_size);
				continue;
			}

			/* if the block is not used */
			block = fs_par2block_get(disk, i);
			if (!block_has_file(block)) {
				/* use an empty block */
				memset(buffer[j], 0, state->block_size);
				continue;
			}

			/* get the file of this block */
			file = fs_par2file_get(disk, i, &file_pos);

			/* if the block is unsynced, errors are expected */
			if (block_has_invalid_parity(block)) {
				/* report that the block and the file are not synced */
				block_is_unsynced = 1;
				file_is_unsynced = 1;
				/* follow */
			}

			/* until now is CPU */
			state_usage_cpu(state);

			/* if the file is different than the current one, close it */
			if (handle[j].file != 0 && handle[j].file != file) {
				/* keep a pointer at the file we are going to close for error reporting */
				struct snapraid_file* report = handle[j].file;
				ret = handle_close(&handle[j]);
				if (ret == -1) {
					/* LCOV_EXCL_START */
					/* This one is really an unexpected error, because we are only reading */
					/* and closing a descriptor should never fail */
					if (errno == EIO) {
						log_tag("error:%u:%s:%s: Close EIO error. %s\n", i, disk->name, esc(report->sub), strerror(errno));
						log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to scrub.\n");
						log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path);
						log_fatal("Stopping at block %u\n", i);
						++io_error;
						goto bail;
					}

					log_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc(report->sub), strerror(errno));
					log_fatal("WARNING! Unexpected close error in a data disk, it isn't possible to scrub.\n");
					log_fatal("Ensure that file '%s' can be accessed.\n", handle[j].path);
					log_fatal("Stopping at block %u\n", i);
					++error;
					goto bail;
					/* LCOV_EXCL_STOP */
				}
			}

			ret = handle_open(&handle[j], file, state->file_mode, log_error, 0);
			if (ret == -1) {
				if (errno == EIO) {
					/* LCOV_EXCL_START */
					log_tag("error:%u:%s:%s: Open EIO error. %s\n", i, disk->name, esc(file->sub), strerror(errno));
					log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to scrub.\n");
					log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path);
					log_fatal("Stopping at block %u\n", i);
					++io_error;
					goto bail;
					/* LCOV_EXCL_STOP */
				}

				log_tag("error:%u:%s:%s: Open error. %s\n", i, disk->name, esc(file->sub), strerror(errno));
				++error;
				error_on_this_block = 1;
				continue;
			}

			/* check if the file is changed */
			if (handle[j].st.st_size != file->size
				|| handle[j].st.st_mtime != file->mtime_sec
				|| STAT_NSEC(&handle[j].st) != file->mtime_nsec
				/* don't check the inode to support filesystem without persistent inodes */
			) {
				/* report that the block and the file are not synced */
				block_is_unsynced = 1;
				file_is_unsynced = 1;
				/* follow */
			}

			/* note that we intentionally don't abort if the file has different attributes */
			/* from the last sync, as we are expected to return errors if running */
			/* in an unsynced array. This is just like the check command. */

			read_size = handle_read(&handle[j], file_pos, buffer[j], state->block_size, log_error, 0);
			if (read_size == -1) {
				if (errno == EIO) {
					log_tag("error:%u:%s:%s: Read EIO error at position %u. %s\n", i, disk->name, esc(file->sub), file_pos, strerror(errno));
					if (io_error >= state->opt.io_error_limit) {
						/* LCOV_EXCL_START */
						log_fatal("DANGER! Too many input/output read error in a data disk, it isn't possible to scrub.\n");
						log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path);
						log_fatal("Stopping at block %u\n", i);
						++io_error;
						goto bail;
						/* LCOV_EXCL_STOP */
					}

					log_error("Input/Output error in file '%s' at position '%u'\n", handle[j].path, file_pos);
					++io_error;
					io_error_on_this_block = 1;
					continue;
				}

				log_tag("error:%u:%s:%s: Read error at position %u. %s\n", i, disk->name, esc(file->sub), file_pos, strerror(errno));
				++error;
				error_on_this_block = 1;
				continue;
			}

			/* until now is disk */
			state_usage_disk(state, disk);

			countsize += read_size;

			/* now compute the hash */
			if (rehash) {
				memhash(state->prevhash, state->prevhashseed, hash, buffer[j], read_size);

				/* compute the new hash, and store it */
				rehandle[j].block = block;
				memhash(state->hash, state->hashseed, rehandle[j].hash, buffer[j], read_size);
			} else {
				memhash(state->hash, state->hashseed, hash, buffer[j], read_size);
			}

			if (block_has_updated_hash(block)) {
				/* compare the hash */
				if (memcmp(hash, block->hash, HASH_SIZE) != 0) {
					unsigned diff = memdiff(hash, block->hash, HASH_SIZE);

					log_tag("error:%u:%s:%s: Data error at position %u, diff bits %u\n", i, disk->name, esc(file->sub), file_pos, diff);

					/* it's a silent error only if we are dealing with synced files */
					if (file_is_unsynced) {
						++error;
						error_on_this_block = 1;
					} else {
						log_error("Data error in file '%s' at position '%u', diff bits %u\n", handle[j].path, file_pos, diff);
						++silent_error;
						silent_error_on_this_block = 1;
					}
					continue;
				}
			}
		}

		/* if we have read all the data required and it's correct, proceed with the parity check */
		if (!error_on_this_block && !silent_error_on_this_block && !io_error_on_this_block) {
			unsigned char* buffer_recov[LEV_MAX];

			/* until now is CPU */
			state_usage_cpu(state);

			/* buffers for parity read and not computed */
			for (l = 0; l < state->level; ++l)
				buffer_recov[l] = buffer[diskmax + state->level + l];
			for (; l < LEV_MAX; ++l)
				buffer_recov[l] = 0;

			/* read the parity */
			for (l = 0; l < state->level; ++l) {
				ret = parity_read(parity[l], i, buffer_recov[l], state->block_size, log_error);
				if (ret == -1) {
					buffer_recov[l] = 0;

					if (errno == EIO) {
						log_tag("parity_error:%u:%s: Read EIO error. %s\n", i, lev_config_name(l), strerror(errno));
						if (io_error >= state->opt.io_error_limit) {
							/* LCOV_EXCL_START */
							log_fatal("DANGER! Too many input/output read error in the %s disk, it isn't possible to scrub.\n", lev_name(l));
							log_fatal("Ensure that disk '%s' is sane and can be read.\n", lev_config_name(l));
							log_fatal("Stopping at block %u\n", i);
							++io_error;
							goto bail;
							/* LCOV_EXCL_STOP */
						}

						log_error("Input/Output error in parity '%s' at position '%u'\n", lev_config_name(l), i);
						++io_error;
						io_error_on_this_block = 1;
						continue;
					}

					log_tag("parity_error:%u:%s: Read error. %s\n", i, lev_config_name(l), strerror(errno));
					++error;
					error_on_this_block = 1;
					continue;
				}

				/* until now is parity */
				state_usage_parity(state, l);
			}

			/* compute the parity */
			raid_gen(diskmax, state->level, state->block_size, buffer);

			/* compare the parity */
			for (l = 0; l < state->level; ++l) {
				if (buffer_recov[l] && memcmp(buffer[diskmax + l], buffer_recov[l], state->block_size) != 0) {
					unsigned diff = memdiff(buffer[diskmax + l], buffer_recov[l], state->block_size);

					log_tag("parity_error:%u:%s: Data error, diff bits %u\n", i, lev_config_name(l), diff);

					/* it's a silent error only if we are dealing with synced blocks */
					if (block_is_unsynced) {
						++error;
						error_on_this_block = 1;
					} else {
						log_fatal("Data error in parity '%s' at position '%u', diff bits %u\n", lev_config_name(l), i, diff);
						++silent_error;
						silent_error_on_this_block = 1;
					}
				}
			}
		}

		if (silent_error_on_this_block || io_error_on_this_block) {
			/* set the error status keeping other info */
			info_set(&state->infoarr, i, info_set_bad(info));
		} else if (error_on_this_block) {
			/* do nothing, as this is a generic error */
			/* likely caused by a not synced array */
		} else {
			/* if rehash is needed */
			if (rehash) {
				/* store all the new hash already computed */
				for (j = 0; j < diskmax; ++j) {
					if (rehandle[j].block)
						memcpy(rehandle[j].block->hash, rehandle[j].hash, HASH_SIZE);
				}
			}

			/* update the time info of the block */
			/* and clear any other flag */
			info_set(&state->infoarr, i, info_make(now, 0, 0, 0));
		}

		/* mark the state as needing write */
		state->need_write = 1;

		/* count the number of processed block */
		++countpos;

		/* progress */
		if (state_progress(state, i, countpos, countmax, countsize)) {
			/* LCOV_EXCL_START */
			break;
			/* LCOV_EXCL_STOP */
		}

		/* autosave */
		if (state->autosave != 0
			&& autosavedone >= autosavelimit /* if we have reached the limit */
			&& autosavemissing >= autosavelimit /* if we have at least a full step to do */
		) {
			autosavedone = 0; /* restart the counter */

			/* until now is CPU */
			state_usage_cpu(state);

			state_progress_stop(state);

			msg_progress("Autosaving...\n");
			state_write(state);

			state_progress_restart(state);

			/* drop until now */
			state_usage_waste(state);
		}
	}

	state_progress_end(state, countpos, countmax, countsize);

	state_usage_print(state);

	if (error || silent_error || io_error) {
		msg_status("\n");
		msg_status("%8u file errors\n", error);
		msg_status("%8u io errors\n", io_error);
		msg_status("%8u data errors\n", silent_error);
	} else {
		/* print the result only if processed something */
		if (countpos != 0)
			msg_status("Everything OK\n");
	}

	if (error)
		log_fatal("WARNING! Unexpected file errors!\n");
	if (io_error)
		log_fatal("DANGER! Unexpected input/output errors! The failing blocks are now marked as bad!\n");
	if (silent_error)
		log_fatal("DANGER! Unexpected data errors! The failing blocks are now marked as bad!\n");
	if (io_error || silent_error) {
		log_fatal("Use 'snapraid status' to list the bad blocks.\n");
		log_fatal("Use 'snapraid -e fix' to recover.\n");
	}

	log_tag("summary:error_file:%u\n", error);
	log_tag("summary:error_io:%u\n", io_error);
	log_tag("summary:error_data:%u\n", silent_error);
	if (error + silent_error + io_error == 0)
		log_tag("summary:exit:ok\n");
	else
		log_tag("summary:exit:error\n");
	log_flush();

bail:
	for (j = 0; j < diskmax; ++j) {
		struct snapraid_file* file = handle[j].file;
		struct snapraid_disk* disk = handle[j].disk;
		ret = handle_close(&handle[j]);
		if (ret == -1) {
			/* LCOV_EXCL_START */
			log_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc(file->sub), strerror(errno));
			log_fatal("DANGER! Unexpected close error in a data disk.\n");
			++error;
			/* continue, as we are already exiting */
			/* LCOV_EXCL_STOP */
		}
	}

	free(handle);
	free(buffer_alloc);
	free(buffer);
	free(rehandle_alloc);

	if (state->opt.expect_recoverable) {
		if (error + silent_error + io_error == 0)
			return -1;
	} else {
		if (error + silent_error + io_error != 0)
			return -1;
	}
	return 0;
}
Example #17
0
static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
        const struct fuse_in_header *hdr, const void *data, size_t data_len)
{
    switch (hdr->opcode) {
    case FUSE_LOOKUP: { /* bytez[] -> entry_out */
        const char* name = data;
        return handle_lookup(fuse, handler, hdr, name);
    }

    case FUSE_FORGET: {
        const struct fuse_forget_in *req = data;
        return handle_forget(fuse, handler, hdr, req);
    }

    case FUSE_GETATTR: { /* getattr_in -> attr_out */
        const struct fuse_getattr_in *req = data;
        return handle_getattr(fuse, handler, hdr, req);
    }

    case FUSE_SETATTR: { /* setattr_in -> attr_out */
        const struct fuse_setattr_in *req = data;
        return handle_setattr(fuse, handler, hdr, req);
    }

//    case FUSE_READLINK:
//    case FUSE_SYMLINK:
    case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
        const struct fuse_mknod_in *req = data;
        const char *name = ((const char*) data) + sizeof(*req);
        return handle_mknod(fuse, handler, hdr, req, name);
    }

    case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
        const struct fuse_mkdir_in *req = data;
        const char *name = ((const char*) data) + sizeof(*req);
        return handle_mkdir(fuse, handler, hdr, req, name);
    }

    case FUSE_UNLINK: { /* bytez[] -> */
        const char* name = data;
        return handle_unlink(fuse, handler, hdr, name);
    }

    case FUSE_RMDIR: { /* bytez[] -> */
        const char* name = data;
        return handle_rmdir(fuse, handler, hdr, name);
    }

    case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
        const struct fuse_rename_in *req = data;
        const char *old_name = ((const char*) data) + sizeof(*req);
        const char *new_name = old_name + strlen(old_name) + 1;
        return handle_rename(fuse, handler, hdr, req, old_name, new_name);
    }

//    case FUSE_LINK:
    case FUSE_OPEN: { /* open_in -> open_out */
        const struct fuse_open_in *req = data;
        return handle_open(fuse, handler, hdr, req);
    }

    case FUSE_READ: { /* read_in -> byte[] */
        const struct fuse_read_in *req = data;
        return handle_read(fuse, handler, hdr, req);
    }

    case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
        const struct fuse_write_in *req = data;
        const void* buffer = (const __u8*)data + sizeof(*req);
        return handle_write(fuse, handler, hdr, req, buffer);
    }

    case FUSE_STATFS: { /* getattr_in -> attr_out */
        return handle_statfs(fuse, handler, hdr);
    }

    case FUSE_RELEASE: { /* release_in -> */
        const struct fuse_release_in *req = data;
        return handle_release(fuse, handler, hdr, req);
    }

    case FUSE_FSYNC: {
        const struct fuse_fsync_in *req = data;
        return handle_fsync(fuse, handler, hdr, req);
    }

//    case FUSE_SETXATTR:
//    case FUSE_GETXATTR:
//    case FUSE_LISTXATTR:
//    case FUSE_REMOVEXATTR:
    case FUSE_FLUSH: {
        return handle_flush(fuse, handler, hdr);
    }

    case FUSE_OPENDIR: { /* open_in -> open_out */
        const struct fuse_open_in *req = data;
        return handle_opendir(fuse, handler, hdr, req);
    }

    case FUSE_READDIR: {
        const struct fuse_read_in *req = data;
        return handle_readdir(fuse, handler, hdr, req);
    }

    case FUSE_RELEASEDIR: { /* release_in -> */
        const struct fuse_release_in *req = data;
        return handle_releasedir(fuse, handler, hdr, req);
    }

//    case FUSE_FSYNCDIR:
    case FUSE_INIT: { /* init_in -> init_out */
        const struct fuse_init_in *req = data;
        return handle_init(fuse, handler, hdr, req);
    }

    default: {
        TRACE("[%d] NOTIMPL op=%d uniq=%llx nid=%llx\n",
                handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
        return -ENOSYS;
    }
    }
}
Example #18
0
/*
 * System call handler
 *
 * retrieves system call number from user space
 * and invokes the requested method
 */
static void
syscall_handler (struct intr_frame *f)
{

        /* retrieve system call number
        and switch to corresponding method */
        unsigned int syscall_number = *((unsigned int*) syscall_get_kernel_address(f->esp));

        switch(syscall_number)
        {
                /* process system calls */
                case SYS_HALT:
                        handle_halt(f);
                        break;

                case SYS_EXIT:
                        handle_exit(f);
                        break;

                case SYS_EXEC:
                        handle_exec(f);
                        break;

                case SYS_WAIT:
                        handle_wait(f);
                        break;

                /* file system calls */
                case SYS_CREATE:
                        handle_create(f);
                        break;
 
                case SYS_REMOVE:
                        handle_remove(f);
                        break;

                case SYS_OPEN:
                        handle_open(f);
                        break;

                case SYS_FILESIZE:
                        handle_filesize(f);
                        break;

                case SYS_READ:
                        handle_read(f);
                        break;

                case SYS_WRITE:
                        handle_write(f);
                        break;

                case SYS_SEEK:
                        handle_seek(f);
                        break;

                case SYS_TELL:
                        handle_tell(f);
                        break;

                case SYS_CLOSE:
                        handle_close(f);
                        break;

                case SYS_CHDIR:
                        handle_chdir(f);
                        break;

                case SYS_MKDIR:
                        handle_mkdir(f);
                        break;

                case SYS_READDIR:
                        handle_readdir(f);
                        break;

                case SYS_ISDIR:
                        handle_isdir(f);
                        break;

                case SYS_INUMBER:
                        handle_inumber(f);
                        break;

                default: /* SYSCALL_ERROR: */
                        handle_no_such_syscall(f);
                        break;
        }
}
Example #19
0
static int state_dry_process(struct snapraid_state* state, struct snapraid_parity_handle** parity, block_off_t blockstart, block_off_t blockmax)
{
	struct snapraid_handle* handle;
	unsigned diskmax;
	block_off_t i;
	unsigned j;
	void* buffer_alloc;
	unsigned char* buffer_aligned;
	int ret;
	data_off_t countsize;
	block_off_t countpos;
	block_off_t countmax;
	unsigned error;
	unsigned l;

	handle = handle_map(state, &diskmax);

	buffer_aligned = malloc_nofail_align(state->block_size, &buffer_alloc);

	error = 0;

	/* drop until now */
	state_usage_waste(state);

	countmax = blockmax - blockstart;
	countsize = 0;
	countpos = 0;
	state_progress_begin(state, blockstart, blockmax, countmax);
	for (i = blockstart; i < blockmax; ++i) {
		/* for each disk, process the block */
		for (j = 0; j < diskmax; ++j) {
			int read_size;
			struct snapraid_block* block = BLOCK_EMPTY;
			struct snapraid_disk* disk = handle[j].disk;

			if (!disk) {
				/* if no disk, nothing to do */
				continue;
			}

			block = disk_block_get(disk, i);

			if (!block_has_file(block)) {
				/* if no file, nothing to do */
				continue;
			}

			/* until now is CPU */
			state_usage_cpu(state);

			/* if the file is closed or different than the current one */
			if (handle[j].file == 0 || handle[j].file != block_file_get(block)) {
				struct snapraid_file* file = handle[j].file;
				ret = handle_close(&handle[j]);
				if (ret == -1) {
					/* LCOV_EXCL_START */
					msg_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc(file->sub), strerror(errno));
					msg_error("DANGER! Unexpected close error in a data disk, it isn't possible to dry.\n");
					msg_error("Stopping at block %u\n", i);
					++error;
					goto bail;
					/* LCOV_EXCL_STOP */
				}

				/* open the file only for reading */
				ret = handle_open(&handle[j], block_file_get(block), state->file_mode, msg_error);
				if (ret == -1) {
					/* LCOV_EXCL_START */
					msg_error("DANGER! Unexpected open error in a data disk, it isn't possible to dry.\n");
					msg_error("Stopping at block %u\n", i);
					++error;
					goto bail;
					/* LCOV_EXCL_STOP */
				}
			}

			/* read from the file */
			read_size = handle_read(&handle[j], block, buffer_aligned, state->block_size, msg_warning);
			if (read_size == -1) {
				msg_tag("error:%u:%s:%s: Read error at position %u\n", i, disk->name, esc(block_file_get(block)->sub), block_file_pos(block));
				++error;
				continue;
			}

			/* until now is disk */
			state_usage_disk(state, disk);

			countsize += read_size;
		}

		/* read the parity */
		for (l = 0; l < state->level; ++l) {
			if (parity[l]) {
				/* until now is CPU */
				state_usage_cpu(state);

				ret = parity_read(parity[l], i, buffer_aligned, state->block_size, msg_warning);
				if (ret == -1) {
					msg_tag("parity_error:%u:%s: Read error\n", i, lev_config_name(l));
					++error;
				}

				/* until now is parity */
				state_usage_parity(state, l);
			}
		}

		/* count the number of processed block */
		++countpos;

		/* progress */
		if (state_progress(state, i, countpos, countmax, countsize)) {
			/* LCOV_EXCL_START */
			break;
			/* LCOV_EXCL_STOP */
		}
	}

	state_progress_end(state, countpos, countmax, countsize);

	state_usage_print(state);

bail:
	/* close all the files left open */
	for (j = 0; j < diskmax; ++j) {
		struct snapraid_file* file = handle[j].file;
		struct snapraid_disk* disk = handle[j].disk;
		ret = handle_close(&handle[j]);
		if (ret == -1) {
			/* LCOV_EXCL_START */
			msg_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc(file->sub), strerror(errno));
			msg_error("DANGER! Unexpected close error in a data disk.\n");
			++error;
			/* continue, as we are already exiting */
			/* LCOV_EXCL_STOP */
		}
	}

	if (error) {
		msg_status("\n");
		msg_status("%8u errors\n", error);
	} else {
		msg_status("Everything OK\n");
	}

	if (error)
		msg_error("DANGER! Unexpected errors!\n");

	free(handle);
	free(buffer_alloc);

	if (error != 0)
		return -1;
	return 0;
}