On 6/16/25 6:30 PM, Chí-Thanh Christopher Nguyễn wrote: > Dear all, > > This is the continuation of a discussion in bug 957712[1], where it was > suggested that portage might in the future allow to replace directories > with symlinks. If you have additional insights or corrections please share. > > PMS 13.2 and 13.4[2] forbid replacing directories with symlinks and > restrict doing the reverse. > > My understanding is that replacing directories with symlinks is a major > no-no for package managers. dpkg[3] and rpm[4] also don't do this, and > if package maintainers want to achieve this result, they have to use > maintenance helper scripts. > > The rationale usually goes like this: Assume package A installs > /foo/bar.txt > and package B installs > /foobar/baz.txt > /foo->/foobar > > Then the resulting directory structure would depend on the merge order > of packages, and if package B for example changes its symlink, then > package A might lose access to its file.
I don't think this is a fair or reasonable assessment. Your rpm link simply says "it is not possible". It then links to a bug report where people discuss the fact that its lack is an "urgent" issue and affected packages cause rpm to be unable to update anything. The rpm developer acknowledges that it's a conceptual flaw in rpm, but "It's not easy problem to solve in RPM". They... do not say why, at all. The official guidance for rpm is to use a pkg_preinst to: - just delete symlinks without checking ANYTHING - unconditionally move directories to .bak (actually .rpmmoved but basically the same), don't delete them because pkg_preinst cannot track CONTENTS and thus doesn't know what can be removed, better safe than sorry and the user can do data recovery, it's up to the user to inspect the moved contents Meanwhile, Debian says much the same thing explicitly in the FAQ: "As dpkg does not currently track file metadata, it does not know if a symlink or directory was switched by a previous package or by the sysadmin. As part of the dpkg credo, preserving human configuration is of utmost importance, and this kind of change has always been considered as so." Notice that MASSIVE qualifier. "dpkg does not currently track file metadata" What???????????????????????????????? They then proceed to say "use pkg_preinst". Here's their documentation on how to handle it: https://manpages.debian.org/unstable/dpkg/dpkg-maintscript-helper.1.en.html#SYMLINK_AND_DIRECTORY_SWITCHES Complete with reconfirmation of the part where they said "dpkg doesn't know if the root account modified the symlink to point elsewhere". "This may seem a simple change to the preinst script at first, however that will result in some problems in case of admin local customization of the symlink" If the symlink object has *changed* from the destination that the package creator expected it to be (i.e. Gentoo's CONTENTS record) as manually written in the pkg_preinst -- remember dpkg simply does not record file metadata so this is *manually* written -- it is safe to replace. If it has been changed by the root user, simply ignore the directory/symlink and trust the user. For a directory object, it checks whether all files currently there are owned by that package, and is therefore safe to upgrade or if any of them are config-protected / belong to other packages / created by the user and just leaves it as a directory. Again, silently. "Trust the user". ... ... This is all genuinely horrible. However, that's a dpkg / rpm problem. It's not some general rule, moreso since both consider it to be a "bug" in their package managers. As a counterpoint, this works flawlessly in pacman (the Arch Linux package manager). In pacman, file conflicts are handled by treating symlink objects like ordinary files. One package cannot install inside another package's symlink, symlinks are not followed. Likewise, but independently, switching between symlinks and directories is fine, to the same extent that switching between files and directories is -- first, check what files are queued for *removal*, then check if the directory would still exist after removals, and if removals *would* remove that directory, it is safe to proceed with the transaction (that removes the files and installs a symlink). > There might be a limited set of situations where such a replacement > could be safe, such as a package replacing its own directory with a > symlink and no other packages owning anything there. But it is > potentially a can of worms. So best keep it that way? No, it's a tremendously useful feature, and conceptually simple. - does the package already own all files in the directory (e.g. file produced by keepdir)? - Yes? Replace. - No? Throw file conflict. The merge order of packages does not matter. If the other package installed first, then "No? Throw file conflict." It was also a conflict today. And it's a conflict with pacman too. If the other package installed second, it works today, it works with this proposal, and it's a conflict with pacman, so we are more flexible and powerful than the only competition. :) But handling it properly as well, "simply" requires preserving a record of files which, when installed, followed a symlink. And update the locations of installed files when their symlink record changes. In fact, solving this would fix longstanding issues with switching split-usr/merged-usr profiles... I think this "limited set of situations" is also the only practical situation anyone cares about, so it makes a lot of sense to support 100% of cases. However, there is a problem. Currently, if portage removes a directory plus all its contents when upgrading to a new version of a cat/pkg, it happens in two stages: - merging new version - "Safely unmerging already-installed instance..." Until step 2, the previously existing directory still exists. It's not obvious that PMS requires this. It doesn't explicitly spell out how the previous version of a package is removed... But, I *think* this should be covered by "The method used to perform the merge is not specified, so long as the end result is correct." If so, that would mean, "Ebuilds must not attempt to merge a regular file on top of any existing file that is not either a regular file or a symlink to a regular file." is talking about "an existing file" owned by a different package. -- Eli Schwartz
OpenPGP_signature.asc
Description: OpenPGP digital signature
