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