dpkg (1.18.25) stretch; urgency=medium
[dpkg] / lib / dpkg / atomic-file.c
CommitLineData
1479465f
GJ
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/atomic-file.h>
34
35#define ATOMIC_FILE_NEW_EXT "-new"
36#define ATOMIC_FILE_OLD_EXT "-old"
37
38struct atomic_file *
39atomic_file_new(const char *filename, enum atomic_file_flags flags)
40{
41 struct atomic_file *file;
42
43 file = m_malloc(sizeof(*file));
44 file->flags = flags;
45 file->fp = NULL;
46 file->name = m_strdup(filename);
47 file->name_new = str_fmt("%s%s", filename, ATOMIC_FILE_NEW_EXT);
48
49 return file;
50}
51
52void
53atomic_file_open(struct atomic_file *file)
54{
55 file->fp = fopen(file->name_new, "w");
56 if (file->fp == NULL)
57 ohshite(_("unable to create new file '%.250s'"),
58 file->name_new);
59 fchmod(fileno(file->fp), 0644);
60
61 push_cleanup(cu_closestream, ~ehflag_normaltidy, NULL, 0, 1, file->fp);
62}
63
64void
65atomic_file_sync(struct atomic_file *file)
66{
67 if (ferror(file->fp))
68 ohshite(_("unable to write new file '%.250s'"), file->name_new);
69 if (fflush(file->fp))
70 ohshite(_("unable to flush new file '%.250s'"), file->name_new);
71 if (fsync(fileno(file->fp)))
72 ohshite(_("unable to sync new file '%.250s'"), file->name_new);
73}
74
75void
76atomic_file_close(struct atomic_file *file)
77{
78 pop_cleanup(ehflag_normaltidy); /* fopen */
79
80 if (fclose(file->fp))
81 ohshite(_("unable to close new file '%.250s'"), file->name_new);
82}
83
84static void
85atomic_file_backup(struct atomic_file *file)
86{
87 char *name_old;
88
89 name_old = str_fmt("%s%s", file->name, ATOMIC_FILE_OLD_EXT);
90
91 if (unlink(name_old) && errno != ENOENT)
92 ohshite(_("error removing old backup file '%s'"), name_old);
93 if (link(file->name, name_old) && errno != ENOENT)
94 ohshite(_("error creating new backup file '%s'"), name_old);
95
96 free(name_old);
97}
98
99void
100atomic_file_remove(struct atomic_file *file)
101{
102 if (unlink(file->name_new))
103 ohshite(_("cannot remove '%.250s'"), file->name_new);
104 if (unlink(file->name) && errno != ENOENT)
105 ohshite(_("cannot remove '%.250s'"), file->name);
106}
107
108void
109atomic_file_commit(struct atomic_file *file)
110{
111 if (file->flags & ATOMIC_FILE_BACKUP)
112 atomic_file_backup(file);
113
114 if (rename(file->name_new, file->name))
115 ohshite(_("error installing new file '%s'"), file->name);
116}
117
118void
119atomic_file_free(struct atomic_file *file)
120{
121 free(file->name_new);
122 free(file->name);
123 free(file);
124}