Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 27 Jan 2015 14:58:44 +0600
From:      Alexey Dokuchaev <danfe@nsu.ru>
To:        hackers@freebsd.org
Subject:   Bug in ln(1), its manpage, or just misunderstanding?
Message-ID:  <20150127085844.GA83566@regency.nsu.ru>

next in thread | raw e-mail | index | archive | help
Hi there,

Per man ln(1), it has -F option which:

    -F    If the target file already exists and is a directory, then remove
          it so that the link may occur.  The -F option should be used with
          either -f or -i options.  If none is specified, -f is implied.  The
          -F option is a no-op unless -s option is specified.

As I read it correctly, it basically removes empty directory so I can place
a link of the same name there:

    $ mkdir foo
    $ ln -sF /etc foo		# result should be: foo -> /etc

However, in ln.c, static int linkit(const char *source, const char *target,
int isdir) contains:

    /*
     * If the target is a directory (and not a symlink if hflag),
     * append the source's name.
     */
    if (isdir ||
        (lstat(target, &sb) == 0 && S_ISDIR(sb.st_mode)) ||
        (!hflag && stat(target, &sb) == 0 && S_ISDIR(sb.st_mode))) {
            if (strlcpy(bbuf, source, sizeof(bbuf)) >= sizeof(bbuf) ||
                (p = basename(bbuf)) == NULL ||
                snprintf(path, sizeof(path), "%s/%s", target, p) >=
                ...

It seems that this logic should be dependent on -F flag, as otherwise source
name is always appended to target and condition that "target file already
exists and is a directory" is impossible to specify and assess:

    $ mkdir foo
    $ ln -sF /etc foo	# result is "foo/etc -> /etc", not "foo -> /etc"

The code is even more bogus: it silently removes directory (and yet returns
an error), which makes it idempotent:

    $ mkdir foo
    $ ln -sF / foo ; echo $?
    ln: foo//: No such file or directory
    1
    < no foo at this point >
    $ ln -sF / foo ; echo $?
    0
    < now foo -> / >
    $ ln -sF / foo ; echo $?
    ln: foo//: Is a directory
    1

./danfe



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20150127085844.GA83566>