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>