dpkg (1.18.25) stretch; urgency=medium
[dpkg] / src / filesdb-hash.c
CommitLineData
1479465f
GJ
1/*
2 * dpkg - main program for package management
3 * filesdb-hash.c - management of database of files installed on system
4 *
5 * Copyright © 2012-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 <string.h>
28#include <stdio.h>
29#include <fcntl.h>
30#include <unistd.h>
31
32#include <dpkg/i18n.h>
33#include <dpkg/dpkg.h>
34#include <dpkg/dpkg-db.h>
35#include <dpkg/debug.h>
36#include <dpkg/fdio.h>
37#include <dpkg/dir.h>
38
39#include "filesdb.h"
40#include "infodb.h"
41
42/*
43 * If mask is nonzero, will not write any file whose filenamenode
44 * has any flag bits set in mask.
45 */
46void
47write_filehash_except(struct pkginfo *pkg, struct pkgbin *pkgbin,
48 struct fileinlist *list, enum filenamenode_flags mask)
49{
50 struct atomic_file *file;
51 const char *hashfile;
52
53 debug(dbg_general, "generating infodb hashfile");
54
55 if (pkg_infodb_has_file(pkg, &pkg->available, HASHFILE))
56 return;
57
58 hashfile = pkg_infodb_get_file(pkg, pkgbin, HASHFILE);
59
60 file = atomic_file_new(hashfile, 0);
61 atomic_file_open(file);
62
63 for (; list; list = list->next) {
64 struct filenamenode *namenode = list->namenode;
65
66 if (mask && (namenode->flags & mask))
67 continue;
68 if (strcmp(namenode->newhash, EMPTYHASHFLAG) == 0)
69 continue;
70
71 fprintf(file->fp, "%s %s\n",
72 namenode->newhash, namenode->name + 1);
73 }
74
75 atomic_file_sync(file);
76 atomic_file_close(file);
77 atomic_file_commit(file);
78 atomic_file_free(file);
79
80 dir_sync_path(pkg_infodb_get_dir());
81}
82
83static void
84parse_filehash_buffer(char *buf, char *buf_end,
85 struct pkginfo *pkg, struct pkgbin *pkgbin)
86{
87 char *thisline, *nextline;
88 const char *pkgname = pkg_name(pkg, pnaw_nonambig);
89
90 for (thisline = buf; thisline < buf_end; thisline = nextline) {
91 struct filenamenode *namenode;
92 char *endline, *hash_end, *filename;
93
94 endline = memchr(thisline, '\n', buf_end - thisline);
95 if (endline == NULL)
96 ohshit(_("control file '%s' for package '%s' is "
97 "missing final newline"), HASHFILE, pkgname);
98
99 /* The md5sum hash has a constant length. */
100 hash_end = thisline + MD5HASHLEN;
101
102 filename = hash_end + 2;
103 if (filename + 1 > endline)
104 ohshit(_("control file '%s' for package '%s' is "
105 "missing value"), HASHFILE, pkgname);
106
107 if (hash_end[0] != ' ' || hash_end[1] != ' ')
108 ohshit(_("control file '%s' for package '%s' is "
109 "missing value separator"), HASHFILE, pkgname);
110 hash_end[0] = '\0';
111
112 /* Where to start next time around. */
113 nextline = endline + 1;
114
115 /* Strip trailing ‘/’. */
116 if (endline > thisline && endline[-1] == '/')
117 endline--;
118 *endline = '\0';
119
120 if (endline == thisline)
121 ohshit(_("control file '%s' for package '%s' "
122 "contains empty filename"), HASHFILE, pkgname);
123
124 debug(dbg_eachfiledetail, "load hash '%s' for filename '%s'",
125 thisline, filename);
126
127 /* Add the file to the list. */
128 namenode = findnamenode(filename, fnn_nocopy);
129 namenode->newhash = thisline;
130 }
131}
132
133void
134parse_filehash(struct pkginfo *pkg, struct pkgbin *pkgbin)
135{
136 static int fd;
137 const char *hashfile;
138 struct stat st;
139
140 hashfile = pkg_infodb_get_file(pkg, pkgbin, HASHFILE);
141
142 fd = open(hashfile, O_RDONLY);
143 if (fd < 0) {
144 if (errno == ENOENT)
145 return;
146
147 ohshite(_("cannot open control file '%s' for package '%s'"),
148 HASHFILE, pkg_name(pkg, pnaw_nonambig));
149 }
150
151 if (fstat(fd, &st) < 0)
152 ohshite(_("cannot stat control file '%s' for package '%s'"),
153 HASHFILE, pkg_name(pkg, pnaw_nonambig));
154
155 if (!S_ISREG(st.st_mode))
156 ohshit(_("control file '%s' for package '%s' is not a regular file"),
157 HASHFILE, pkg_name(pkg, pnaw_nonambig));
158
159 if (st.st_size > 0) {
160 char *buf, *buf_end;
161
162 buf = nfmalloc(st.st_size);
163 buf_end = buf + st.st_size;
164
165 if (fd_read(fd, buf, st.st_size) < 0)
166 ohshite(_("cannot read control file '%s' for package '%s'"),
167 HASHFILE, pkg_name(pkg, pnaw_nonambig));
168
169 parse_filehash_buffer(buf, buf_end, pkg, pkgbin);
170 }
171
172 if (close(fd))
173 ohshite(_("cannot close control file '%s' for package '%s'"),
174 HASHFILE, pkg_name(pkg, pnaw_nonambig));
175}