[pacman-dev] lstat issue / fileconflict001 pactest

Xavier shiningxc at gmail.com
Sat Nov 10 10:55:55 EST 2007


Following the discussion started in the comments of bug 7484, because I think
it's more appropriate :
http://bugs.archlinux.org/task/7484#comment20837

I recently discovered that a trailing / is very important when using lstat,
for directory symlinks. In the following situation :
symdir -> realdir/
lstat(symdir) stats the link itself, but lstat(symdir/) stats realdir.
So lstat(symdir/) seems equivalent to stat(symdir).

The archive extraction code in add.c that Dan rewrote didn't take this into
consideration, so he added a new _alpm_lstat that removes the trailing / when
there is one :
http://projects.archlinux.org/git/?p=pacman.git;a=commit;h=b55abdce7aebb142ce79da3aa3645afe7693a3c4
A little typo in _alpm_lstat (path instead of newpath) made this change not active yet.
As Dan noticed, fixing this makes fileconflict001 pass. The only purpose of
this mail is explaining why.

So in this pactest, we have the following situation :
dir/realdir/
dir/symdir -> realdir

Then pkg1 installs dir/realdir/file , and pkg2 installs dir/symdir/file .
Since in this case, symdir points to realdir, pkg1 and pkg2 have a
fileconflict on "file".
But if fileconflict001 pass after the bugfix mentioned above, it's not
because pacman detects there is a package<->package conflict between
dir/realdir/file and dir/symdir/file.
Instead, it detects a filesystem <-> package conflict between dir/symdir/
from pkg2 (which is a real directory there), and the dir/symdir symlink on
the filesystem. So that's plain wrong.

The fileconflict code currently does a lstat(dir/symdir/), which doesn't stat
the symdir symlink, but the real directory realdir.
So it treated dir/symdir/ as a directory, and ignored it :

336 /* stat the file - if it exists, do some checks /
337 if(_alpm_lstat(path, &buf) != 0) {
338   continue;
339 }
340 if(S_ISDIR(buf.st_mode)) {
341   _alpm_log(PM_LOG_DEBUG, "%s is a directory, not a conflict\n", path);

Now, with the new behavior of _alpm_lstat, the code does a lstat(dir/symdir),
which stats the symlink. And the following code will treat this as a
conflict.

The case of fileconflict001 is probably another situation easier to detect
during the transaction (coupled with a rollback system), rather than
beforehand.
Otherwise, maybe the file conflict code should keep using the normal lstat,
instead of _alpm_lstat which removes the trailing /.




More information about the pacman-dev mailing list