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
;