Exemple #1
0
static int o_stream_temp_move_to_fd(struct temp_ostream *tstream)
{
	string_t *path;

	if (tstream->fd_tried)
		return -1;
	tstream->fd_tried = TRUE;

	path = t_str_new(128);
	str_append(path, tstream->temp_path_prefix);
	tstream->fd = safe_mkstemp_hostpid(path, 0600, (uid_t)-1, (gid_t)-1);
	if (tstream->fd == -1) {
		i_error("safe_mkstemp(%s) failed: %m", str_c(path));
		return -1;
	}
	if (i_unlink(str_c(path)) < 0) {
		i_close_fd(&tstream->fd);
		return -1;
	}
	if (write_full(tstream->fd, tstream->buf->data, tstream->buf->used) < 0) {
		i_error("write(%s) failed: %m", str_c(path));
		i_close_fd(&tstream->fd);
		return -1;
	}
	/* make the fd available also to o_stream_get_fd(),
	   e.g. for unit tests */
	tstream->ostream.fd = tstream->fd;
	tstream->fd_size = tstream->buf->used;
	buffer_free(&tstream->buf);
	return 0;
}
Exemple #2
0
static int index_attachment_open_temp_fd(void *context)
{
	struct mail_save_context *ctx = context;
	struct mail_storage *storage = ctx->transaction->box->storage;
	string_t *temp_path;
	int fd;

	temp_path = t_str_new(256);
	mail_user_set_get_temp_prefix(temp_path, storage->user->set);
	fd = safe_mkstemp_hostpid(temp_path, 0600, (uid_t)-1, (gid_t)-1);
	if (fd == -1) {
		mail_storage_set_critical(storage,
			"safe_mkstemp(%s) failed: %m", str_c(temp_path));
		return -1;
	}
	if (unlink(str_c(temp_path)) < 0) {
		mail_storage_set_critical(storage,
			"unlink(%s) failed: %m", str_c(temp_path));
		i_close_fd(&fd);
		return -1;
	}
	return fd;
}
static int
sieve_file_storage_save_to(struct sieve_file_storage *fstorage,
	string_t *temp_path, struct istream *input,
	const char *target)
{
	struct sieve_storage *storage = &fstorage->storage;
	struct ostream *output;
	int fd;

	// FIXME: move this to base class
	// FIXME: use io_stream_temp

	fd = safe_mkstemp_hostpid
		(temp_path, fstorage->file_create_mode, (uid_t)-1, (gid_t)-1);
	if ( fd < 0 ) {
		if ( errno == EACCES ) {
			sieve_storage_set_critical(storage,
				"Failed to create temporary file: %s",
				eacces_error_get_creating("open", str_c(temp_path)));
		} else {
			sieve_storage_set_critical(storage,
				"Failed to create temporary file: open(%s) failed: %m",
				str_c(temp_path));
		}
		return -1;
	}

	output = o_stream_create_fd(fd, 0);
	switch ( o_stream_send_istream(output, input) ) {
	case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
		break;
	case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
	case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
		i_unreached();
	case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
		sieve_storage_set_critical(storage,
			"read(%s) failed: %s", i_stream_get_name(input),
			i_stream_get_error(input));
		o_stream_destroy(&output);
		i_unlink(str_c(temp_path));
		return -1;
	case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
		sieve_storage_set_critical(storage,
			"write(%s) failed: %s", str_c(temp_path),
			o_stream_get_error(output));
		o_stream_destroy(&output);
		i_unlink(str_c(temp_path));
		return -1;
	}
	o_stream_destroy(&output);

	if ( rename(str_c(temp_path), target) < 0 ) {
		if ( ENOQUOTA(errno) ) {
			sieve_storage_set_error(storage,
				SIEVE_ERROR_NO_QUOTA,
				"Not enough disk quota");
		} else if ( errno == EACCES ) {
			sieve_storage_set_critical(storage,
				"%s", eacces_error_get("rename", target));
		} else {
			sieve_storage_set_critical(storage,
				"rename(%s, %s) failed: %m",
				str_c(temp_path), target);
		}
		i_unlink(str_c(temp_path));
	}
	return 0;
}
int sieve_binary_save
(struct sieve_binary *sbin, const char *path, bool update, mode_t save_mode,
	enum sieve_error *error_r)
{
	int result, fd;
	string_t *temp_path;
	struct ostream *stream;

	if ( error_r != NULL )
		*error_r = SIEVE_ERROR_NONE;

	/* Check whether saving is necessary */
	if ( !update && sbin->path != NULL && strcmp(sbin->path, path) == 0 ) {
		if ( sbin->svinst->debug ) {
			sieve_sys_debug(sbin->svinst, "binary save: not saving binary %s, "
				"because it is already stored", path);
		}
		return 0;
	}

	/* Open it as temp file first, as not to overwrite an existing just yet */
	temp_path = t_str_new(256);
	str_append(temp_path, path);
	str_append_c(temp_path, '.');
	fd = safe_mkstemp_hostpid(temp_path, save_mode, (uid_t)-1, (gid_t)-1);
	if ( fd < 0 ) {
		if ( errno == EACCES ) {
			sieve_sys_error(sbin->svinst,
				"binary save: failed to create temporary file: %s",
				eacces_error_get_creating("open", str_c(temp_path)));
			if ( error_r != NULL )
				*error_r = SIEVE_ERROR_NO_PERMISSION;
		} else {
			sieve_sys_error(sbin->svinst,
				"binary save: failed to create temporary file: open(%s) failed: %m",
				str_c(temp_path));
			if ( error_r != NULL )
				*error_r = SIEVE_ERROR_TEMP_FAILURE;
		}
		return -1;
	}

	/* Save binary */
	result = 1;
	stream = o_stream_create_fd(fd, 0, FALSE);
	if ( !_sieve_binary_save(sbin, stream) ) {
		result = -1;
		if ( error_r != NULL )
			*error_r = SIEVE_ERROR_TEMP_FAILURE;
	}
	o_stream_destroy(&stream);

	/* Close saved binary */
	if ( close(fd) < 0 ) {
		sieve_sys_error(sbin->svinst,
			"binary save: failed to close temporary file: "
			"close(fd=%s) failed: %m", str_c(temp_path));
	}

	/* Replace any original binary atomically */
	if ( result && (rename(str_c(temp_path), path) < 0) ) {
		if ( errno == EACCES ) {
			sieve_sys_error(sbin->svinst, "binary save: failed to save binary: %s",
				eacces_error_get_creating("rename", path));
			if ( error_r != NULL )
				*error_r = SIEVE_ERROR_NO_PERMISSION;
		} else {
			sieve_sys_error(sbin->svinst, "binary save: failed to save binary: "
				"rename(%s, %s) failed: %m", str_c(temp_path), path);
			if ( error_r != NULL )
				*error_r = SIEVE_ERROR_TEMP_FAILURE;
		}
		result = -1;
	}

	if ( result < 0 ) {
		/* Get rid of temp output (if any) */
		if ( unlink(str_c(temp_path)) < 0 && errno != ENOENT ) {
			sieve_sys_error(sbin->svinst,
				"binary save: failed to clean up after error: unlink(%s) failed: %m",
				str_c(temp_path));
		}
	} else {
		if ( sbin->path == NULL ) {
			sbin->path = p_strdup(sbin->pool, path);
		}
	}

	return result;
}