This is part of the fix for #108587.
* lib/dpkg-db.h (conffile): Add `obsolete' field.
* lib/dump.c (w_conffiles): Write "obsolete" at the
end of conffile entry if obsolete is set.
* lib/fields.c (f_conffiles): Parse entries for
obsolete conffiles correctly.
* src/filesdb.h (filenamenode.flags): Add new
flag for obsolete conffiles.
* src/remove.c (removal_bulk_remove_configfiles):
Handle obsolete conffiles.
* src/archives.c (newconff_append): New function
to append a filenamenode to a fileinlist.
(addfiletolist): New function to add a filenamenode
to a tarcontext.
(tarobject): Use new addfiletolist function.
Handle case where a new package takes over
an obsolete conffile from another package.
* src/archives.h: Add declaration of the
addfiletolist function.
* src/processarc.c (process_archive): Use new
newconff_append function from archives.c.
Detect obsoleted conffiles and mark them as such.
* src/help.c (chmodsafe_unlink): Make it possible
to differentiate between failed chmod and failed
unlink by adding a new `failed' argument which
will be set to the name of the failed command.
(chmodsafe_unlink_statted): New function that
can be called if we already have a stat result for
the file/directory to be removed.
(ensure_pathname_nonexisting): Give better error
messages by utilizing the changes to
chmodsafe_unlink.
* src/main.h: Reflect changes in archives.c
and help.c (add declarations for newconff_append
and chmodsafe_unlink_statted and change the
one of chmodsafe_unlink).
(conffopt): Add new isold flag.
a warning that was produced when trying to
backup a non-existant file.
+ * lib/dpkg-db.h (conffile): Add `obsolete' field.
+ * lib/dump.c (w_conffiles): Write "obsolete" at the
+ end of conffile entry if obsolete is set.
+ * lib/fields.c (f_conffiles): Parse entries for
+ obsolete conffiles correctly.
+ * src/filesdb.h (filenamenode.flags): Add new
+ flag for obsolete conffiles.
+ * src/remove.c (removal_bulk_remove_configfiles):
+ Handle obsolete conffiles.
+ * src/archives.c (newconff_append): New function
+ to append a filenamenode to a fileinlist.
+ (addfiletolist): New function to add a filenamenode
+ to a tarcontext.
+ (tarobject): Use new addfiletolist function.
+ Handle case where a new package takes over
+ an obsolete conffile from another package.
+ * src/archives.h: Add declaration of the
+ addfiletolist function.
+ * src/processarc.c (process_archive): Use new
+ newconff_append function from archives.c.
+ Detect obsoleted conffiles and mark them as such.
+ * src/help.c (chmodsafe_unlink): Make it possible
+ to differentiate between failed chmod and failed
+ unlink by adding a new `failed' argument which
+ will be set to the name of the failed command.
+ (chmodsafe_unlink_statted): New function that
+ can be called if we already have a stat result for
+ the file/directory to be removed.
+ (ensure_pathname_nonexisting): Give better error
+ messages by utilizing the changes to
+ chmodsafe_unlink.
+ * src/main.h: Reflect changes in archives.c
+ and help.c (add declarations for newconff_append
+ and chmodsafe_unlink_statted and change the
+ one of chmodsafe_unlink).
+ (conffopt): Add new isold flag.
+
2006-02-10 James R. Van Zandt <jrvz@comcast.net>
* man/C/dpkg.1: Document the default log file. The behaviour in case
variables.
* On package configuration, differentiate between modified and
deleted configuration files (Ian Jackson). Closes: #351361
+ * Improve processing of disappearing conffiles (Ian Jackson).
+ This is part of the fix for #108587.
* Let dpkg-source -x touch all patched files to have the same
timestamp to mitigate time-skew problems (Denis Barbier).
Closes: #105750
struct conffile *next;
const char *name;
const char *hash;
+ int obsolete;
};
struct filedetails {
if (i!=pifp->conffiles) varbufaddc(vb,'\n');
varbufaddc(vb,' '); varbufaddstr(vb,i->name); varbufaddc(vb,' ');
varbufaddstr(vb,i->hash);
+ if (i->obsolete) varbufaddstr(vb," obsolete");
}
if (flags&fw_printheader)
varbufaddc(vb,'\n');
"in Config-Version string `%.250s': %.250s"),value,emsg);
}
+void conffvalue_lastword(const char *value, const char *from,
+ const char *endent,
+ const char **word_start_r, int *word_len_r,
+ const char **new_from_r,
+ const char *filename, int lno,
+ FILE *warnto, int *warncount, struct pkginfo *pigp) {
+ /* the code in f_conffiles ensures that value[-1]==' ', which is helpful */
+ const char *lastspc;
+
+ if (from <= value+1) goto malformed;
+ for (lastspc= from-1; *lastspc != ' '; lastspc--);
+ if (lastspc <= value+1 || lastspc >= endent-1) goto malformed;
+
+ *new_from_r= lastspc;
+ *word_start_r= lastspc + 1;
+ *word_len_r= (int)(from - *word_start_r);
+ return;
+
+malformed:
+ parseerr(NULL,filename,lno, warnto,warncount,pigp,0,
+ _("value for `conffiles' has malformatted line `%.*s'"),
+ (int)(endent-value > 250 ? 250 : endent-value), value);
+}
+
void f_conffiles(struct pkginfo *pigp, struct pkginfoperfile *pifp,
enum parsedbflags flags,
const char *filename, int lno, FILE *warnto, int *warncount,
const char *value, const struct fieldinfo *fip) {
+ static const char obsolete_str[]= "obsolete";
struct conffile **lastp, *newlink;
- const char *endent, *endfn;
- int c, namelen, hashlen;
+ const char *endent, *endfn, *hashstart;
+ int c, namelen, hashlen, obsolete;
char *newptr;
lastp= &pifp->conffiles;
if (c != ' ') parseerr(NULL,filename,lno, warnto,warncount,pigp,0, _("value for"
" `conffiles' has line starting with non-space `%c'"), c);
for (endent= value; (c= *endent)!=0 && c != '\n'; endent++);
- for (endfn= endent; *endfn != ' '; endfn--);
- if (endfn <= value+1 || endfn >= endent-1)
- parseerr(NULL,filename,lno, warnto,warncount,pigp,0,
- _("value for `conffiles' has malformatted line `%.*s'"),
- (int)(endent-value > 250 ? 250 : endent-value), value);
+ conffvalue_lastword(value, endent, endent,
+ &hashstart, &hashlen, &endfn,
+ filename,lno,warnto,warncount,pigp);
+ obsolete= (hashlen == sizeof(obsolete_str)-1 &&
+ !memcmp(hashstart, obsolete_str, hashlen));
+ if (obsolete)
+ conffvalue_lastword(value, endfn, endent,
+ &hashstart, &hashlen, &endfn,
+ filename,lno,warnto,warncount,pigp);
newlink= nfmalloc(sizeof(struct conffile));
value= skip_slash_dotslash(value);
namelen= (int)(endfn-value);
memcpy(newptr+1,value,namelen);
newptr[namelen+1]= 0;
newlink->name= newptr;
- hashlen= (int)(endent-endfn)-1; newptr= nfmalloc(hashlen+1);
- memcpy(newptr,endfn+1,hashlen); newptr[hashlen]= 0;
+ newptr= nfmalloc(hashlen+1);
+ memcpy(newptr,hashstart,hashlen); newptr[hashlen]= 0;
newlink->hash= newptr;
+ newlink->obsolete= obsolete;
newlink->next =NULL;
*lastp= newlink;
lastp= &newlink->next;
errno= e; return r;
}
+struct fileinlist *addfiletolist(struct tarcontext *tc,
+ struct filenamenode *namenode) {
+ struct fileinlist *nifd;
+
+ nifd= obstack_alloc(&tar_obs, sizeof(struct fileinlist));
+ nifd->namenode= namenode;
+ nifd->next= 0; *tc->newfilesp= nifd; tc->newfilesp= &nifd->next;
+ return nifd;
+}
+
int tarobject(struct TarInfo *ti) {
static struct varbuf conffderefn, hardlinkfn, symlinkfn;
const char *usename;
-
+
+ struct conffile *conff;
struct tarcontext *tc= (struct tarcontext*)ti->UserData;
int statr, fd, i, existingdirectory, keepexisting;
size_t r;
- struct stat stab, stabd;
+ struct stat stab, stabtmp;
char databuf[TARBLKSZ];
struct fileinlist *nifd, **oldnifd;
struct pkginfo *divpkg, *otherpkg;
* been stripped by TarExtractor (lib/tarfn.c).
*/
oldnifd= tc->newfilesp;
- nifd= obstack_alloc(&tar_obs, sizeof(struct fileinlist));
- nifd->namenode= findnamenode(ti->Name, 0);
- nifd->next= 0; *tc->newfilesp= nifd; tc->newfilesp= &nifd->next;
+ nifd= addfiletolist(tc, findnamenode(ti->Name, 0));
nifd->namenode->flags |= fnnf_new_inarchive;
debug(dbg_eachfile,
break;
case Directory:
/* If it's already an existing directory, do nothing. */
- if (!stat(fnamevb.buf,&stabd) && S_ISDIR(stabd.st_mode)) {
+ if (!stat(fnamevb.buf,&stabtmp) && S_ISDIR(stabtmp.st_mode)) {
debug(dbg_eachfiledetail,"tarobject Directory exists");
existingdirectory= 1;
}
if (otherpkg->status == stat_configfiles) continue;
/* Perhaps we're removing a conflicting package ? */
if (otherpkg->clientdata->istobe == itb_remove) continue;
+
+ /* Is the file an obsolete conffile in the other package
+ * and a conffile in the new package ? */
+ if ((nifd->namenode->flags & fnnf_new_conff) &&
+ !statr && S_ISREG(stab.st_mode)) {
+ for (conff= otherpkg->installed.conffiles;
+ conff;
+ conff= conff->next) {
+ if (!conff->obsolete)
+ continue;
+ if (stat(conff->name, &stabtmp))
+ if (errno == ENOENT || errno == ENOTDIR || errno == ELOOP)
+ continue;
+ if (stabtmp.st_dev == stab.st_dev &&
+ stabtmp.st_ino == stab.st_ino)
+ break;
+ }
+ if (conff)
+ debug(dbg_eachfiledetail,"tarobject other's obsolete conffile");
+ /* processarc.c will have copied its hash already. */
+ continue;
+ }
+
if (does_replace(tc->pkg,&tc->pkg->available,otherpkg)) {
printf(_("Replacing files in old package %s ...\n"),otherpkg->name);
otherpkg->clientdata->replacingfilesandsaid= 1;
}
}
+struct fileinlist *newconff_append(struct fileinlist ***newconffileslastp_io,
+ struct filenamenode *namenode) {
+ struct fileinlist *newconff;
+
+ newconff= m_malloc(sizeof(struct fileinlist));
+ newconff->next= 0;
+ newconff->namenode= namenode;
+ **newconffileslastp_io= newconff;
+ *newconffileslastp_io= &newconff->next;
+ return newconff;
+}
+
/* vi: ts=8 sw=2
*/
void check_conflict(struct dependency *dep, struct pkginfo *pkg,
const char *pfilename);
+struct fileinlist *addfiletolist(struct tarcontext *tc,
+ struct filenamenode *namenode);
+
extern int cleanup_pkg_failed, cleanup_conflictor_failed;
#endif /* ARCHIVES_H */
fnnf_new_conff= 000001, /* in the newconffiles list */
fnnf_new_inarchive= 000002, /* in the new filesystem archive */
fnnf_old_conff= 000004, /* in the old package's conffiles list */
+ fnnf_obs_conff= 000100, /* obsolete conffile */
fnnf_elide_other_lists= 000010, /* must remove from other packages' lists */
fnnf_no_atomic_overwrite= 000020, /* >=1 instance is a dir, cannot rename over */
fnnf_placed_on_disk= 000040, /* new file has been placed on the disk */
while (searchconff) {
namenode= findnamenode(searchconff->name, 0); /* XXX */
namenode->flags |= fnnf_old_conff;
+ if (!namenode->oldhash)
+ namenode->oldhash= searchconff->hash;
debug(dbg_conffdetail, "oldconffsetflags `%s' namenode %p flags %o",
searchconff->name, namenode, namenode->flags);
searchconff= searchconff->next;
}
}
-int chmodsafe_unlink(const char *pathname) {
+int chmodsafe_unlink(const char *pathname, const char **failed) {
+ /* Sets *failed to `chmod' or `unlink' if those calls fail (which is
+ * always unexpected). If stat fails it leaves *failed alone. */
struct stat stab;
if (lstat(pathname,&stab)) return -1;
- if (S_ISREG(stab.st_mode) ? (stab.st_mode & 07000) :
- !(S_ISLNK(stab.st_mode) || S_ISDIR(stab.st_mode) ||
- S_ISFIFO(stab.st_mode) || S_ISSOCK(stab.st_mode))) {
+ *failed= N_("unlink");
+ return chmodsafe_unlink_statted(pathname, &stab, failed);
+}
+
+int chmodsafe_unlink_statted(const char *pathname, const struct stat *stab,
+ const char **failed) {
+ /* Sets *failed to `chmod'' if that call fails (which is always
+ * unexpected). If unlink fails it leaves *failed alone. */
+ if (S_ISREG(stab->st_mode) ? (stab->st_mode & 07000) :
+ !(S_ISLNK(stab->st_mode) || S_ISDIR(stab->st_mode) ||
+ S_ISFIFO(stab->st_mode) || S_ISSOCK(stab->st_mode))) {
/* We chmod it if it is 1. a sticky or set-id file, or 2. an unrecognised
- * object (ie, not a file, link, directory, fifo or socket
+ * object (ie, not a file, link, directory, fifo or socket)
*/
- if (chmod(pathname,0600)) return -1;
+ if (chmod(pathname,0600)) { *failed= N_("chmod"); return -1; }
}
if (unlink(pathname)) return -1;
return 0;
void ensure_pathname_nonexisting(const char *pathname) {
int c1;
- const char *u;
+ const char *u, *failed;
u= skip_slash_dotslash(pathname);
assert(*u);
debug(dbg_eachfile,"ensure_pathname_nonexisting `%s'",pathname);
if (!rmdir(pathname)) return; /* Deleted it OK, it was a directory. */
if (errno == ENOENT || errno == ELOOP) return;
+ failed= N_("delete");
if (errno == ENOTDIR) {
/* Either it's a file, or one of the path components is. If one
* of the path components is this will fail again ...
*/
- if (!chmodsafe_unlink(pathname)) return; /* OK, it was */
+ if (!chmodsafe_unlink(pathname, &failed)) return; /* OK, it was */
if (errno == ENOTDIR) return;
}
- if (errno != ENOTEMPTY) /* Huh ? */
- ohshite(_("failed to rmdir/unlink `%.255s'"),pathname);
+ if (errno != ENOTEMPTY) { /* Huh ? */
+ char mbuf[250];
+ snprintf(mbuf, sizeof(mbuf), N_("failed to %s `%%.255s'"), failed);
+ ohshite(_(mbuf),pathname);
+ }
c1= m_fork();
if (!c1) {
execlp(RM,"rm","-rf","--",pathname,(char*)0);
cfof_prompt = 001,
cfof_keep = 002,
cfof_install = 004,
- cfof_backup = 0100,
- cfof_newconff = 0200,
- cfof_isnew = 0400,
+ cfof_backup = 00100,
+ cfof_newconff = 00200,
+ cfof_isnew = 00400,
+ cfof_isold = 01000,
cfom_main = 007,
cfo_keep = cfof_keep,
cfo_prompt_keep = cfof_keep | cfof_prompt,
void archivefiles(const char *const *argv);
void process_archive(const char *filename);
int wanttoinstall(struct pkginfo *pkg, const struct versionrevision *ver, int saywhy);
+struct fileinlist *newconff_append(struct fileinlist ***newconffileslastp_io,
+ struct filenamenode *namenode);
/* from update.c */
const char *pkgadminfile(struct pkginfo *pkg, const char *whichfile);
void oldconffsetflags(const struct conffile *searchconff);
void ensure_pathname_nonexisting(const char *pathname);
-int chmodsafe_unlink(const char *pathname); /* chmod 600, then unlink */
+int chmodsafe_unlink(const char *pathname, const char **failed);
+int chmodsafe_unlink_statted(const char *pathname, const struct stat *stab,
+ const char **failed);
void checkpath(void);
struct filenamenode *namenodetouse(struct filenamenode*, struct pkginfo*);
struct pkginfo *pkg, *otherpkg, *divpkg;
char *cidir, *cidirrest, *p;
char *pfilenamebuf, conffilenamebuf[MAXCONFFILENAME];
- const char *pfilename, *newinfofilename;
+ const char *pfilename, *newinfofilename, *failed;
struct fileinlist *newconff, **newconffileslastp;
struct fileinlist *cfile;
struct reversefilelistiter rlistit;
DIR *dsd;
struct filenamenode *namenode;
struct dirent *de;
- struct stat stab;
+ struct stat stab, oldfs;
struct packageinlist *deconpil, *deconpiltemp;
cleanup_pkg_failed= cleanup_conflictor_failed= 0;
while (p > conffilenamebuf && isspace(p[-1])) --p;
if (p == conffilenamebuf) continue;
*p= 0;
- newconff= m_malloc(sizeof(struct fileinlist));
- newconff->next= 0;
- newconff->namenode= findnamenode(conffilenamebuf, 0);
- *newconffileslastp= newconff;
- newconffileslastp= &newconff->next;
- newconff->namenode->oldhash= NEWCONFFILEFLAG;
+ namenode= findnamenode(conffilenamebuf, 0);
+ namenode->oldhash= NEWCONFFILEFLAG;
+ newconff= newconff_append(&newconffileslastp, namenode);
+
/* Let's see if any packages have this file. If they do we
* check to see if they listed it as a conffile, and if they did
* we copy the hash across. Since (for plain file conffiles,
xit_conff_hashcopy_srch:
if (searchconff) {
newconff->namenode->oldhash= searchconff->hash;
+ /* we don't copy `obsolete'; it's not obsolete in the new package */
} else {
debug(dbg_conff,"process_archive conffile `%s' no package, no hash",
newconff->namenode->name);
* package isn't one we're already processing, and the package's
* list becomes empty as a result, we `vanish' the package. This
* means that we run its postrm with the `disappear' argument, and
- * put the package in the `not-installed' state. Its conffiles are
- * ignored and forgotten about.
+ * put the package in the `not-installed' state. If it had any
+ * conffiles, their hashes and ownership will have been transferred
+ * already, so we just ignore those and forget about them from the
+ * point of view of the disappearing package.
*
* NOTE THAT THE OLD POSTRM IS RUN AFTER THE NEW PREINST, since the
* files get replaced `as we go'.
*/
reversefilelist_init(&rlistit,pkg->clientdata->files);
while ((namenode= reversefilelist_next(&rlistit))) {
- if ((namenode->flags & fnnf_old_conff) ||
- (namenode->flags & fnnf_new_conff) ||
+ if ((namenode->flags & fnnf_new_conff) ||
(namenode->flags & fnnf_new_inarchive))
continue;
if (!stat(namenode->name,&stab) && S_ISDIR(stab.st_mode)) {
fnamevb.used= fnameidlu;
varbufaddstr(&fnamevb, namenodetouse(namenode,pkg)->name);
varbufaddc(&fnamevb,0);
- if (!rmdir(fnamevb.buf)) continue;
- if (errno == ENOENT || errno == ELOOP) continue;
- if (errno == ENOTDIR) {
+
+ if (lstat(fnamevb.buf, &oldfs)) {
+ if (!(errno == ENOENT || errno == ELOOP || errno == ENOTDIR))
+ fprintf(stderr,
+ _("dpkg: warning - could not stat old file `%.250s'"
+ " so not deleting it: %s"),
+ fnamevb.buf, strerror(errno));
+ continue;
+ }
+ if (S_ISDIR(oldfs.st_mode)) {
+ if (rmdir(fnamevb.buf)) {
+ fprintf(stderr,
+ _("dpkg: warning - unable to delete old directory"
+ " `%.250s': %s\n"), namenode->name, strerror(errno));
+ } else if ((namenode->flags & fnnf_old_conff)) {
+ fprintf(stderr,
+ _("dpkg: warning - old conffile `%.250s' was an empty"
+ " directory (and has now been deleted)\n"),
+ namenode->name);
+ }
+ } else {
/* Ok, it's an old file, but is it really not in the new package?
+ * It might be known by a different name because of symlinks.
+ *
* We need to check to make sure, so we stat the file, then compare
* it to the new list. If we find a dev/inode match, we assume they
* are the same file, and leave it alone. NOTE: we don't check in
* the process a little leaner. We are only worried about new ones
* since ones that stayed the same don't really apply here.
*/
- struct stat oldfs;
- int donotrm = 0;
+ struct fileinlist *sameas= 0;
/* If we can't stat the old or new file, or it's a directory,
* we leave it up to the normal code
*/
debug(dbg_eachfile, "process_archive: checking %s for same files on "
- "upgrade/downgrade", fnamevb.buf);
- if (!lstat(fnamevb.buf, &oldfs) && !S_ISDIR(oldfs.st_mode)) {
- for (cfile = newfileslist; cfile; cfile = cfile->next) {
- if (!cfile->namenode->filestat) {
- cfile->namenode->filestat = (struct stat *) nfmalloc(sizeof(struct stat));
- if (lstat(cfile->namenode->name, cfile->namenode->filestat)) {
- cfile->namenode->filestat= 0;
- continue;
- }
- }
- if (S_ISDIR(cfile->namenode->filestat->st_mode))
+ "upgrade/downgrade", fnamevb.buf);
+
+ for (cfile= newfileslist; cfile; cfile= cfile->next) {
+ if (!cfile->namenode->filestat) {
+ cfile->namenode->filestat= nfmalloc(sizeof(struct stat));
+ if (lstat(cfile->namenode->name, cfile->namenode->filestat)) {
+ if (!(errno == ENOENT || errno == ELOOP || errno == ENOTDIR))
+ ohshite(_("unable to stat other new file `%.250s'"),
+ cfile->namenode->name);
+ memset(cfile->namenode->filestat, 0,
+ sizeof(cfile->namenode->filestat));
continue;
- if (oldfs.st_dev == cfile->namenode->filestat->st_dev &&
- oldfs.st_ino == cfile->namenode->filestat->st_ino) {
- donotrm = 1;
- debug(dbg_eachfile, "process_archive: not removing %s, since it matches %s",
- fnamevb.buf, cfile->namenode->name);
}
}
- } else
- debug(dbg_eachfile, "process_archive: could not stat %s, skipping", fnamevb.buf);
- if (donotrm) continue;
- {
- /*
- * If file to remove is a device or s[gu]id, change its mode
- * so that a malicious user cannot use it even if it's linked
- * to another file.
- */
- struct stat stat_buf;
- if (lstat(fnamevb.buf,&stat_buf)==0) {
- if (S_ISCHR(stat_buf.st_mode) || S_ISBLK(stat_buf.st_mode))
- chmod(fnamevb.buf, 0);
- if (stat_buf.st_mode & (S_ISUID|S_ISGID))
- chmod(fnamevb.buf, stat_buf.st_mode & ~(S_ISUID|S_ISGID));
+ if (!cfile->namenode->filestat->st_mode) continue;
+ if (oldfs.st_dev == cfile->namenode->filestat->st_dev &&
+ oldfs.st_ino == cfile->namenode->filestat->st_ino) {
+ if (sameas)
+ fprintf(stderr, _("dpkg: warning - old file `%.250s' is the same"
+ " as several new files! (both `%.250s' and `%.250s'"),
+ fnamevb.buf,
+ sameas->namenode->name, cfile->namenode->name);
+ sameas= cfile;
+ debug(dbg_eachfile, "process_archive: not removing %s,"
+ " since it matches %s", fnamevb.buf, cfile->namenode->name);
}
}
- if (!unlink(fnamevb.buf)) continue;
- if (errno == ENOTDIR) continue;
- }
- fprintf(stderr,
- _("dpkg: warning - unable to delete old file `%.250s': %s\n"),
- namenode->name, strerror(errno));
+
+ if ((namenode->flags & fnnf_old_conff)) {
+ if (sameas) {
+ if (sameas->namenode->flags & fnnf_new_conff) {
+ if (!strcmp(sameas->namenode->oldhash, NEWCONFFILEFLAG)) {
+ sameas->namenode->oldhash= namenode->oldhash;
+ debug(dbg_eachfile, "process_archive: old conff %s"
+ " is same as new conff %s, copying hash",
+ namenode->name, sameas->namenode->name);
+ } else {
+ debug(dbg_eachfile, "process_archive: old conff %s"
+ " is same as new conff %s but latter already has hash",
+ namenode->name, sameas->namenode->name);
+ }
+ }
+ } else {
+ debug(dbg_eachfile, "process_archive: old conff %s"
+ " is disappearing", namenode->name);
+ namenode->flags |= fnnf_obs_conff;
+ newconff_append(&newconffileslastp, namenode);
+ addfiletolist(&tc, namenode);
+ }
+ continue;
+ }
+
+ if (sameas)
+ continue;
+
+ failed= N_("delete");
+ if (chmodsafe_unlink_statted(fnamevb.buf, &oldfs, &failed)) {
+ char mbuf[250];
+ snprintf(mbuf, sizeof(mbuf),
+ N_("dpkg: warning - unable to %s old file `%%.250s': %%s\n"),
+ failed);
+ fprintf(stderr, _(mbuf), namenode->name, strerror(errno));
+ }
+
+ } /* !S_ISDIR */
}
/* OK, now we can write the updated files-in-this package list,
newiconff->next= 0;
newiconff->name= nfstrsave(cfile->namenode->name);
newiconff->hash= nfstrsave(cfile->namenode->oldhash);
+ newiconff->obsolete= !!(cfile->namenode->flags & fnnf_obs_conff);
*iconffileslastp= newiconff;
iconffileslastp= &newiconff->next;
}
*
* Note that we don't ever delete things that were in the old
* package as a conffile and don't appear at all in the new.
+ * They stay recorded as obsolete conffiles and will eventually
+ * (if not taken over by another package) be forgotten.
*/
for (cfile= newfileslist; cfile; cfile= cfile->next) {
if (cfile->namenode->flags & fnnf_new_conff) continue;
for (conff= pkg->installed.conffiles; conff; conff= conff->next) {
static struct varbuf fnvb, removevb;
+ if (conff->obsolete) {
+ debug(dbg_conffdetail, "removal_bulk conffile obsolete %s",
+ conff->name);
+ continue;
+ }
varbufreset(&fnvb);
r= conffderef(pkg, &fnvb, conff->name);
debug(dbg_conffdetail, "removal_bulk conffile `%s' (= `%s')",