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; }
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; }