diff options
author | jilles <jilles@FreeBSD.org> | 2010-04-21 21:57:03 +0000 |
---|---|---|
committer | jilles <jilles@FreeBSD.org> | 2010-04-21 21:57:03 +0000 |
commit | 1a724f1dcaab30bf93e2b9f14ba5cb859e401086 (patch) | |
tree | 9b1536d2aaea25358ac97eadee8361f3d7c641c7 /bin/ln | |
parent | 31257c45676b6404dfd580abbffec543f3a32962 (diff) | |
download | FreeBSD-src-1a724f1dcaab30bf93e2b9f14ba5cb859e401086.zip FreeBSD-src-1a724f1dcaab30bf93e2b9f14ba5cb859e401086.tar.gz |
ln: Allow a trailing slash when creating a link to a directory.
In the 'ln source... directory' synopsis, the basename of each source
determines the name of the created link. Determine this using basename(3)
instead of strrchr(..., '/') which is incorrect if the pathname ends in a
slash.
The patch is somewhat changed to allow for basename(3) implementations that
change the passed pathname, and to fix the -w option's checking also.
The code to compare directory entries only applies to hard links, which
cannot be created to directories using ln.
Example:
ln -s /etc/defaults/ /tmp
This should create a symlink named defaults.
PR: 121568
Submitted by: Ighighi
MFC after: 1 week
Diffstat (limited to 'bin/ln')
-rw-r--r-- | bin/ln/ln.c | 27 |
1 files changed, 13 insertions, 14 deletions
diff --git a/bin/ln/ln.c b/bin/ln/ln.c index d779392..fc3afc1 100644 --- a/bin/ln/ln.c +++ b/bin/ln/ln.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <err.h> #include <errno.h> #include <fcntl.h> +#include <libgen.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> @@ -226,6 +227,7 @@ linkit(const char *source, const char *target, int isdir) int ch, exists, first; char path[PATH_MAX]; char wbuf[PATH_MAX]; + char bbuf[PATH_MAX]; if (!sflag) { /* If source doesn't exist, quit now. */ @@ -248,11 +250,9 @@ linkit(const char *source, const char *target, int isdir) if (isdir || (lstat(target, &sb) == 0 && S_ISDIR(sb.st_mode)) || (!hflag && stat(target, &sb) == 0 && S_ISDIR(sb.st_mode))) { - if ((p = strrchr(source, '/')) == NULL) - p = source; - else - ++p; - if (snprintf(path, sizeof(path), "%s/%s", target, p) >= + if (strlcpy(bbuf, source, sizeof(bbuf)) >= sizeof(bbuf) || + (p = basename(bbuf)) == NULL || + snprintf(path, sizeof(path), "%s/%s", target, p) >= (ssize_t)sizeof(path)) { errno = ENAMETOOLONG; warn("%s", source); @@ -276,15 +276,14 @@ linkit(const char *source, const char *target, int isdir) * absolute path of the source, by appending `source' * to the parent directory of the target. */ - p = strrchr(target, '/'); - if (p != NULL) - p++; - else - p = target; - (void)snprintf(wbuf, sizeof(wbuf), "%.*s%s", - (int)(p - target), target, source); - if (stat(wbuf, &sb) != 0) - warn("warning: %s", source); + strlcpy(bbuf, target, sizeof(bbuf)); + p = dirname(bbuf); + if (p != NULL) { + (void)snprintf(wbuf, sizeof(wbuf), "%s/%s", + p, source); + if (stat(wbuf, &sb) != 0) + warn("warning: %s", source); + } } } |