2 * dpkg - main program for package management
3 * filesdb.c - management of database of files installed on system
5 * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 * Copyright © 2000,2001 Wichert Akkerman <wakkerma@debian.org>
7 * Copyright © 2008-2014 Guillem Jover <guillem@debian.org>
9 * This is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
26 #ifdef HAVE_LINUX_FIEMAP_H
27 #include <linux/fiemap.h>
29 #include <sys/ioctl.h>
32 #include <sys/types.h>
44 #include <dpkg/i18n.h>
45 #include <dpkg/dpkg.h>
46 #include <dpkg/dpkg-db.h>
47 #include <dpkg/string.h>
48 #include <dpkg/path.h>
50 #include <dpkg/fdio.h>
51 #include <dpkg/pkg-array.h>
52 #include <dpkg/progress.h>
58 /*** filepackages support for tracking packages owning a file. ***/
60 struct filepackages_iterator {
61 struct pkg_list *pkg_node;
64 struct filepackages_iterator *
65 filepackages_iter_new(struct filenamenode *fnn)
67 struct filepackages_iterator *iter;
69 iter = m_malloc(sizeof(*iter));
70 iter->pkg_node = fnn->packages;
76 filepackages_iter_next(struct filepackages_iterator *iter)
78 struct pkg_list *pkg_node;
80 if (iter->pkg_node == NULL)
83 pkg_node = iter->pkg_node;
84 iter->pkg_node = pkg_node->next;
90 filepackages_iter_free(struct filepackages_iterator *iter)
95 /*** Generic data structures and routines. ***/
97 static bool allpackagesdone = false;
101 ensure_package_clientdata(struct pkginfo *pkg)
105 pkg->clientdata = nfmalloc(sizeof(struct perpackagestate));
106 pkg->clientdata->istobe = PKG_ISTOBE_NORMAL;
107 pkg->clientdata->color = PKG_CYCLE_WHITE;
108 pkg->clientdata->enqueued = false;
109 pkg->clientdata->fileslistvalid = false;
110 pkg->clientdata->files = NULL;
111 pkg->clientdata->replacingfilesandsaid = 0;
112 pkg->clientdata->cmdline_seen = 0;
113 pkg->clientdata->listfile_phys_offs = 0;
114 pkg->clientdata->trigprocdeferred = NULL;
117 void note_must_reread_files_inpackage(struct pkginfo *pkg) {
118 allpackagesdone = false;
119 ensure_package_clientdata(pkg);
120 pkg->clientdata->fileslistvalid = false;
123 enum pkg_filesdb_load_status {
124 PKG_FILESDB_LOAD_NONE = 0,
125 PKG_FILESDB_LOAD_INPROGRESS = 1,
126 PKG_FILESDB_LOAD_DONE = 2,
129 static enum pkg_filesdb_load_status saidread = PKG_FILESDB_LOAD_NONE;
132 * Erase the files saved in pkg.
135 pkg_files_blank(struct pkginfo *pkg)
137 struct fileinlist *current;
139 /* Anything to empty? */
140 if (!pkg->clientdata)
143 for (current= pkg->clientdata->files;
145 current= current->next) {
146 struct pkg_list *pkg_node, *pkg_prev = NULL;
148 /* For each file that used to be in the package,
149 * go through looking for this package's entry in the list
150 * of packages containing this file, and blank it out. */
151 for (pkg_node = current->namenode->packages;
153 pkg_node = pkg_node->next) {
154 if (pkg_node->pkg == pkg) {
156 pkg_prev->next = pkg_node->next;
158 current->namenode->packages = pkg_node->next;
160 /* The actual filelist links were allocated using nfmalloc, so
161 * we shouldn't free them. */
167 pkg->clientdata->files = NULL;
170 static struct fileinlist **
171 pkg_files_add_file(struct pkginfo *pkg, struct filenamenode *namenode,
172 struct fileinlist **file_tail)
174 struct fileinlist *newent;
175 struct pkg_list *pkg_node;
177 ensure_package_clientdata(pkg);
179 if (file_tail == NULL)
180 file_tail = &pkg->clientdata->files;
182 /* Make sure we're at the end. */
183 while ((*file_tail) != NULL) {
184 file_tail = &((*file_tail)->next);
187 /* Create a new node. */
188 newent = nfmalloc(sizeof(struct fileinlist));
189 newent->namenode = namenode;
192 file_tail = &newent->next;
194 /* Add pkg to newent's package list. */
195 pkg_node = nfmalloc(sizeof(*pkg_node));
197 pkg_node->next = newent->namenode->packages;
198 newent->namenode->packages = pkg_node;
200 /* Return the position for the next guy. */
205 * Load the list of files in this package into memory, or update the
206 * list if it is there but stale.
209 ensure_packagefiles_available(struct pkginfo *pkg)
212 const char *filelistfile;
213 struct fileinlist **lendp;
214 struct stat stat_buf;
215 char *loaded_list, *loaded_list_end, *thisline, *nextline, *ptr;
217 if (pkg->clientdata && pkg->clientdata->fileslistvalid)
219 ensure_package_clientdata(pkg);
221 /* Throw away any stale data, if there was any. */
222 pkg_files_blank(pkg);
224 /* Packages which aren't installed don't have a files list. */
225 if (pkg->status == PKG_STAT_NOTINSTALLED) {
226 pkg->clientdata->fileslistvalid = true;
230 filelistfile = pkg_infodb_get_file(pkg, &pkg->installed, LISTFILE);
234 fd= open(filelistfile,O_RDONLY);
238 ohshite(_("unable to open files list file for package '%.250s'"),
239 pkg_name(pkg, pnaw_nonambig));
241 if (pkg->status != PKG_STAT_CONFIGFILES &&
242 dpkg_version_is_informative(&pkg->configversion)) {
243 warning(_("files list file for package '%.250s' missing; assuming "
244 "package has no files currently installed"),
245 pkg_name(pkg, pnaw_nonambig));
247 pkg->clientdata->files = NULL;
248 pkg->clientdata->fileslistvalid = true;
252 push_cleanup(cu_closefd, ehflag_bombout, NULL, 0, 1, &fd);
254 if (fstat(fd, &stat_buf))
255 ohshite(_("unable to stat files list file for package '%.250s'"),
256 pkg_name(pkg, pnaw_nonambig));
258 if (!S_ISREG(stat_buf.st_mode))
259 ohshit(_("files list for package '%.250s' is not a regular file"),
260 pkg_name(pkg, pnaw_nonambig));
262 if (stat_buf.st_size) {
263 loaded_list = nfmalloc(stat_buf.st_size);
264 loaded_list_end = loaded_list + stat_buf.st_size;
266 if (fd_read(fd, loaded_list, stat_buf.st_size) < 0)
267 ohshite(_("reading files list for package '%.250s'"),
268 pkg_name(pkg, pnaw_nonambig));
270 lendp= &pkg->clientdata->files;
271 thisline = loaded_list;
272 while (thisline < loaded_list_end) {
273 struct filenamenode *namenode;
275 ptr = memchr(thisline, '\n', loaded_list_end - thisline);
277 ohshit(_("files list file for package '%.250s' is missing final newline"),
278 pkg_name(pkg, pnaw_nonambig));
279 /* Where to start next time around. */
281 /* Strip trailing ‘/’. */
282 if (ptr > thisline && ptr[-1] == '/') ptr--;
283 /* Add the file to the list. */
285 ohshit(_("files list file for package '%.250s' contains empty filename"),
286 pkg_name(pkg, pnaw_nonambig));
289 namenode = findnamenode(thisline, fnn_nocopy);
290 lendp = pkg_files_add_file(pkg, namenode, lendp);
294 pop_cleanup(ehflag_normaltidy); /* fd = open() */
296 ohshite(_("error closing files list file for package '%.250s'"),
297 pkg_name(pkg, pnaw_nonambig));
301 pkg->clientdata->fileslistvalid = true;
304 #if defined(HAVE_LINUX_FIEMAP_H)
306 pkg_sorter_by_listfile_phys_offs(const void *a, const void *b)
308 const struct pkginfo *pa = *(const struct pkginfo **)a;
309 const struct pkginfo *pb = *(const struct pkginfo **)b;
311 /* We can't simply subtract, because the difference may be greater than
313 if (pa->clientdata->listfile_phys_offs < pb->clientdata->listfile_phys_offs)
315 else if (pa->clientdata->listfile_phys_offs > pb->clientdata->listfile_phys_offs)
322 pkg_files_optimize_load(struct pkg_array *array)
327 /* Get the filesystem block size. */
328 if (statfs(pkg_infodb_get_dir(), &fs) < 0)
331 /* Sort packages by the physical location of their list files, so that
332 * scanning them later will minimize disk drive head movements. */
333 for (i = 0; i < array->n_pkgs; i++) {
334 struct pkginfo *pkg = array->pkgs[i];
336 struct fiemap fiemap;
337 struct fiemap_extent extent;
339 const char *listfile;
342 ensure_package_clientdata(pkg);
344 if (pkg->status == PKG_STAT_NOTINSTALLED ||
345 pkg->clientdata->listfile_phys_offs != 0)
348 pkg->clientdata->listfile_phys_offs = -1;
350 listfile = pkg_infodb_get_file(pkg, &pkg->installed, LISTFILE);
352 fd = open(listfile, O_RDONLY);
356 memset(&fm, 0, sizeof(fm));
357 fm.fiemap.fm_start = 0;
358 fm.fiemap.fm_length = fs.f_bsize;
359 fm.fiemap.fm_flags = 0;
360 fm.fiemap.fm_extent_count = 1;
362 if (ioctl(fd, FS_IOC_FIEMAP, (unsigned long)&fm) == 0)
363 pkg->clientdata->listfile_phys_offs = fm.fiemap.fm_extents[0].fe_physical;
368 pkg_array_sort(array, pkg_sorter_by_listfile_phys_offs);
370 #elif defined(HAVE_POSIX_FADVISE)
372 pkg_files_optimize_load(struct pkg_array *array)
376 /* Ask the kernel to start preloading the list files, so as to get a
377 * boost when later we actually load them. */
378 for (i = 0; i < array->n_pkgs; i++) {
379 struct pkginfo *pkg = array->pkgs[i];
380 const char *listfile;
383 listfile = pkg_infodb_get_file(pkg, &pkg->installed, LISTFILE);
385 fd = open(listfile, O_RDONLY | O_NONBLOCK);
387 posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED);
394 pkg_files_optimize_load(struct pkg_array *array)
399 void ensure_allinstfiles_available(void) {
400 struct pkg_array array;
402 struct progress progress;
405 if (allpackagesdone) return;
406 if (saidread < PKG_FILESDB_LOAD_DONE) {
407 int max = pkg_db_count_pkg();
409 saidread = PKG_FILESDB_LOAD_INPROGRESS;
410 progress_init(&progress, _("(Reading database ... "), max);
413 pkg_array_init_from_db(&array);
415 pkg_files_optimize_load(&array);
417 for (i = 0; i < array.n_pkgs; i++) {
419 ensure_packagefiles_available(pkg);
421 if (saidread == PKG_FILESDB_LOAD_INPROGRESS)
422 progress_step(&progress);
425 pkg_array_destroy(&array);
427 allpackagesdone = true;
429 if (saidread == PKG_FILESDB_LOAD_INPROGRESS) {
430 progress_done(&progress);
431 printf(P_("%d file or directory currently installed.)\n",
432 "%d files and directories currently installed.)\n", nfiles),
434 saidread = PKG_FILESDB_LOAD_DONE;
438 void ensure_allinstfiles_available_quiet(void) {
439 saidread = PKG_FILESDB_LOAD_DONE;
440 ensure_allinstfiles_available();
444 * If mask is nonzero, will not write any file whose filenamenode
445 * has any flag bits set in mask.
448 write_filelist_except(struct pkginfo *pkg, struct pkgbin *pkgbin,
449 struct fileinlist *list, enum filenamenode_flags mask)
451 struct atomic_file *file;
452 struct fileinlist *node;
453 const char *listfile;
455 listfile = pkg_infodb_get_file(pkg, pkgbin, LISTFILE);
457 file = atomic_file_new(listfile, 0);
458 atomic_file_open(file);
460 for (node = list; node; node = node->next) {
461 if (!(mask && (node->namenode->flags & mask))) {
462 fputs(node->namenode->name, file->fp);
463 putc('\n', file->fp);
467 atomic_file_sync(file);
468 atomic_file_close(file);
469 atomic_file_commit(file);
470 atomic_file_free(file);
472 dir_sync_path(pkg_infodb_get_dir());
474 note_must_reread_files_inpackage(pkg);
478 * Initializes an iterator that appears to go through the file
479 * list ‘files’ in reverse order, returning the namenode from
480 * each. What actually happens is that we walk the list here,
481 * building up a reverse list, and then peel it apart one
485 reversefilelist_init(struct reversefilelistiter *iter, struct fileinlist *files)
487 struct fileinlist *newent;
491 newent= m_malloc(sizeof(struct fileinlist));
492 newent->namenode= files->namenode;
493 newent->next = iter->todo;
499 struct filenamenode *
500 reversefilelist_next(struct reversefilelistiter *iter)
502 struct filenamenode *ret;
503 struct fileinlist *todo;
509 iter->todo = todo->next;
515 * Clients must call this function to clean up the reversefilelistiter
516 * if they wish to break out of the iteration before it is all done.
517 * Calling this function is not necessary if reversefilelist_next has
518 * been called until it returned 0.
521 reversefilelist_abort(struct reversefilelistiter *iter)
523 while (reversefilelist_next(iter));
526 struct fileiterator {
527 struct filenamenode *namenode;
531 /* This must always be a prime for optimal performance.
532 * This is the closest one to 2^18 (262144). */
535 static struct filenamenode *bins[BINS];
537 struct fileiterator *
538 files_db_iter_new(void)
540 struct fileiterator *iter;
542 iter = m_malloc(sizeof(struct fileiterator));
543 iter->namenode = NULL;
549 struct filenamenode *
550 files_db_iter_next(struct fileiterator *iter)
552 struct filenamenode *r= NULL;
554 while (!iter->namenode) {
555 if (iter->nbinn >= BINS)
557 iter->namenode = bins[iter->nbinn++];
560 iter->namenode = r->next;
566 files_db_iter_free(struct fileiterator *iter)
571 void filesdbinit(void) {
572 struct filenamenode *fnn;
575 for (i=0; i<BINS; i++)
576 for (fnn= bins[i]; fnn; fnn= fnn->next) {
579 fnn->newhash = EMPTYHASHFLAG;
580 fnn->filestat = NULL;
589 for (i = 0; i < BINS; i++)
593 struct filenamenode *findnamenode(const char *name, enum fnnflags flags) {
594 struct filenamenode **pointerp, *newnode;
595 const char *orig_name = name;
597 /* We skip initial slashes and ‘./’ pairs, and add our own single
599 name = path_skip_slash_dotslash(name);
601 pointerp = bins + (str_fnv_hash(name) % (BINS));
603 /* XXX: Why is the assert needed? It's checking already added entries. */
604 assert((*pointerp)->name[0] == '/');
605 if (strcmp((*pointerp)->name + 1, name) == 0)
607 pointerp= &(*pointerp)->next;
609 if (*pointerp) return *pointerp;
611 if (flags & fnn_nonew)
614 newnode= nfmalloc(sizeof(struct filenamenode));
615 newnode->packages = NULL;
616 if((flags & fnn_nocopy) && name > orig_name && name[-1] == '/')
617 newnode->name = name - 1;
619 char *newname= nfmalloc(strlen(name)+2);
620 newname[0]= '/'; strcpy(newname+1,name);
621 newnode->name= newname;
624 newnode->next = NULL;
625 newnode->divert = NULL;
626 newnode->statoverride = NULL;
627 newnode->oldhash = NULL;
628 newnode->newhash = EMPTYHASHFLAG;
629 newnode->filestat = NULL;
630 newnode->trig_interested = NULL;