int sieve_file_storage_save_finish (struct sieve_storage_save_context *sctx) { struct sieve_file_save_context *fsctx = (struct sieve_file_save_context *)sctx; struct sieve_storage *storage = sctx->storage; int output_errno; if ( sctx->failed && fsctx->fd == -1 ) { /* tmp file creation failed */ return -1; } T_BEGIN { output_errno = fsctx->output->stream_errno; o_stream_destroy(&fsctx->output); if ( fsync(fsctx->fd) < 0 ) { sieve_storage_set_critical(storage, "save: " "fsync(%s) failed: %m", fsctx->tmp_path); sctx->failed = TRUE; } if ( close(fsctx->fd) < 0 ) { sieve_storage_set_critical(storage, "save: " "close(%s) failed: %m", fsctx->tmp_path); sctx->failed = TRUE; } fsctx->fd = -1; if ( sctx->failed ) { /* delete the tmp file */ if (unlink(fsctx->tmp_path) < 0 && errno != ENOENT) { sieve_storage_sys_warning(storage, "save: " "unlink(%s) failed: %m", fsctx->tmp_path); } fsctx->tmp_path = NULL; errno = output_errno; if ( ENOQUOTA(errno) ) { sieve_storage_set_error(storage, SIEVE_ERROR_NO_QUOTA, "Not enough disk quota"); } else if ( errno != 0 ) { sieve_storage_set_critical(storage, "save: " "write(%s) failed: %m", fsctx->tmp_path); } } } T_END; return ( sctx->failed ? -1 : 0 ); }
void sieve_file_storage_save_cancel(struct sieve_storage_save_context *sctx) { struct sieve_file_save_context *fsctx = (struct sieve_file_save_context *)sctx; struct sieve_storage *storage = sctx->storage; if (fsctx->tmp_path != NULL && unlink(fsctx->tmp_path) < 0 && errno != ENOENT) { sieve_storage_sys_warning(storage, "save: " "unlink(%s) failed: %m", fsctx->tmp_path); } i_assert(fsctx->output == NULL); }
static int sieve_file_storage_script_move (struct sieve_file_save_context *fsctx, const char *dst) { struct sieve_storage_save_context *sctx = &fsctx->context; struct sieve_storage *storage = sctx->storage; int result = 0; T_BEGIN { /* Using rename() to ensure existing files are replaced * without conflicts with other processes using the same * file. The kernel wont fully delete the original until * all processes have closed the file. */ if (rename(fsctx->tmp_path, dst) == 0) result = 0; else { result = -1; 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, "save: " "Failed to save Sieve script: " "%s", eacces_error_get("rename", dst)); } else { sieve_storage_set_critical(storage, "save: " "rename(%s, %s) failed: %m", fsctx->tmp_path, dst); } } /* Always destroy temp file */ if (unlink(fsctx->tmp_path) < 0 && errno != ENOENT) { sieve_storage_sys_warning(storage, "save: " "unlink(%s) failed: %m", fsctx->tmp_path); } } T_END; return result; }
int sieve_file_storage_quota_havespace (struct sieve_storage *storage, const char *scriptname, size_t size, enum sieve_storage_quota *quota_r, uint64_t *limit_r) { struct sieve_file_storage *fstorage = (struct sieve_file_storage *)storage; struct dirent *dp; DIR *dirp; uint64_t script_count = 1; uint64_t script_storage = size; int result = 1; /* Open the directory */ if ( (dirp = opendir(fstorage->path)) == NULL ) { sieve_storage_set_critical(storage, "quota: opendir(%s) failed: %m", fstorage->path); return -1; } /* Scan all files */ for (;;) { const char *name; bool replaced = FALSE; /* Read next entry */ errno = 0; if ( (dp = readdir(dirp)) == NULL ) { if ( errno != 0 ) { sieve_storage_set_critical(storage, "quota: readdir(%s) failed: %m", fstorage->path); result = -1; } break; } /* Parse filename */ name = sieve_script_file_get_scriptname(dp->d_name); /* Ignore non-script files */ if ( name == NULL ) continue; /* Don't list our active sieve script link if the link * resides in the script dir (generally a bad idea). */ i_assert( fstorage->link_path != NULL ); if ( *(fstorage->link_path) == '\0' && strcmp(fstorage->active_fname, dp->d_name) == 0 ) continue; if ( strcmp(name, scriptname) == 0 ) replaced = TRUE; /* Check count quota if necessary */ if ( storage->max_scripts > 0 ) { if ( !replaced ) { script_count++; if ( script_count > storage->max_scripts ) { *quota_r = SIEVE_STORAGE_QUOTA_MAXSCRIPTS; *limit_r = storage->max_scripts; result = 0; break; } } } /* Check storage quota if necessary */ if ( storage->max_storage > 0 ) { const char *path; struct stat st; path = t_strconcat(fstorage->path, "/", dp->d_name, NULL); if ( stat(path, &st) < 0 ) { sieve_storage_sys_warning(storage, "quota: stat(%s) failed: %m", path); continue; } if ( !replaced ) { script_storage += st.st_size; if ( script_storage > storage->max_storage ) { *quota_r = SIEVE_STORAGE_QUOTA_MAXSTORAGE; *limit_r = storage->max_storage; result = 0; break; } } } } /* Close directory */ if ( closedir(dirp) < 0 ) { sieve_storage_set_critical(storage, "quota: closedir(%s) failed: %m", fstorage->path); } return result; }