Branch data Line data Source code
1 : : /* 2 : : * libdpkg - Debian packaging suite library routines 3 : : * atomic-file.c - atomic file helper functions 4 : : * 5 : : * Copyright © 2011-2014 Guillem Jover <guillem@debian.org> 6 : : * 7 : : * This is free software; you can redistribute it and/or modify 8 : : * it under the terms of the GNU General Public License as published by 9 : : * the Free Software Foundation; either version 2 of the License, or 10 : : * (at your option) any later version. 11 : : * 12 : : * This is distributed in the hope that it will be useful, 13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 : : * GNU General Public License for more details. 16 : : * 17 : : * You should have received a copy of the GNU General Public License 18 : : * along with this program. If not, see <https://www.gnu.org/licenses/>. 19 : : */ 20 : : 21 : : #include <config.h> 22 : : #include <compat.h> 23 : : 24 : : #include <sys/stat.h> 25 : : 26 : : #include <errno.h> 27 : : #include <stdlib.h> 28 : : #include <stdio.h> 29 : : #include <unistd.h> 30 : : 31 : : #include <dpkg/i18n.h> 32 : : #include <dpkg/dpkg.h> 33 : : #include <dpkg/dir.h> 34 : : #include <dpkg/atomic-file.h> 35 : : 36 : : #define ATOMIC_FILE_NEW_EXT "-new" 37 : : #define ATOMIC_FILE_OLD_EXT "-old" 38 : : 39 : : struct atomic_file * 40 : 30 : atomic_file_new(const char *filename, enum atomic_file_flags flags) 41 : : { 42 : : struct atomic_file *file; 43 : : 44 : 30 : file = m_malloc(sizeof(*file)); 45 : 30 : file->flags = flags; 46 : 30 : file->fp = NULL; 47 : 30 : file->name = m_strdup(filename); 48 : 30 : file->name_new = str_fmt("%s%s", filename, ATOMIC_FILE_NEW_EXT); 49 : : 50 : 30 : return file; 51 : : } 52 : : 53 : : void 54 : 29 : atomic_file_open(struct atomic_file *file) 55 : : { 56 : 29 : file->fp = fopen(file->name_new, "w"); 57 [ + + - + ]: 29 : if (file->fp == NULL && file->flags & ATOMIC_FILE_MKPATH) { 58 [ # # ]: 0 : if (dir_make_path_parent(file->name, 0755) < 0) 59 : 0 : ohshite(_("cannot create base directory for %s"), 60 : : file->name); 61 : : 62 : 0 : file->fp = fopen(file->name_new, "w"); 63 : : } 64 [ + + ]: 29 : if (file->fp == NULL) 65 : 1 : ohshite(_("unable to create new file '%.250s'"), 66 : : file->name_new); 67 : 28 : fchmod(fileno(file->fp), 0644); 68 : : 69 : 28 : push_cleanup(cu_closestream, ~ehflag_normaltidy, 1, file->fp); 70 : 28 : } 71 : : 72 : : void 73 : 28 : atomic_file_sync(struct atomic_file *file) 74 : : { 75 [ - + ]: 28 : if (ferror(file->fp)) 76 : 0 : ohshite(_("unable to write new file '%.250s'"), file->name_new); 77 [ + + ]: 28 : if (fflush(file->fp)) 78 : 1 : ohshite(_("unable to flush new file '%.250s'"), file->name_new); 79 [ - + ]: 27 : if (fsync(fileno(file->fp))) 80 : 0 : ohshite(_("unable to sync new file '%.250s'"), file->name_new); 81 : 27 : } 82 : : 83 : : void 84 : 27 : atomic_file_close(struct atomic_file *file) 85 : : { 86 : 27 : pop_cleanup(ehflag_normaltidy); /* fopen */ 87 : : 88 [ - + ]: 27 : if (fclose(file->fp)) 89 : 0 : ohshite(_("unable to close new file '%.250s'"), file->name_new); 90 : 27 : } 91 : : 92 : : static void 93 : 27 : atomic_file_backup(struct atomic_file *file) 94 : : { 95 : : char *name_old; 96 : : 97 : 27 : name_old = str_fmt("%s%s", file->name, ATOMIC_FILE_OLD_EXT); 98 : : 99 [ + + + + ]: 27 : if (unlink(name_old) && errno != ENOENT) 100 : 1 : ohshite(_("error removing old backup file '%s'"), name_old); 101 [ - + - - ]: 26 : if (link(file->name, name_old) && errno != ENOENT) 102 : 0 : ohshite(_("error creating new backup file '%s'"), name_old); 103 : : 104 : 26 : free(name_old); 105 : 26 : } 106 : : 107 : : void 108 : 0 : atomic_file_remove(struct atomic_file *file) 109 : : { 110 [ # # ]: 0 : if (unlink(file->name_new)) 111 : 0 : ohshite(_("cannot remove '%.250s'"), file->name_new); 112 [ # # # # ]: 0 : if (unlink(file->name) && errno != ENOENT) 113 : 0 : ohshite(_("cannot remove '%.250s'"), file->name); 114 : 0 : } 115 : : 116 : : void 117 : 27 : atomic_file_commit(struct atomic_file *file) 118 : : { 119 [ + - ]: 27 : if (file->flags & ATOMIC_FILE_BACKUP) 120 : 27 : atomic_file_backup(file); 121 : : 122 [ - + ]: 26 : if (rename(file->name_new, file->name)) 123 : 0 : ohshite(_("error installing new file '%s'"), file->name); 124 : 26 : } 125 : : 126 : : void 127 : 27 : atomic_file_free(struct atomic_file *file) 128 : : { 129 : 27 : free(file->name_new); 130 : 27 : free(file->name); 131 : 27 : free(file); 132 : 27 : }