chiark / gitweb /
lib/dpkg/tarfn.c: Kludge `tar_header_decode' to handle spurious `errno'.
[dpkg] / src / filesdb-hash.c
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  */
46 void
47 write_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
83 static void
84 parse_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
133 void
134 parse_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 }