From 1a724f1dcaab30bf93e2b9f14ba5cb859e401086 Mon Sep 17 00:00:00 2001 From: jilles Date: Wed, 21 Apr 2010 21:57:03 +0000 Subject: 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 --- bin/ln/ln.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'bin/ln') 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 #include #include +#include #include #include #include @@ -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); + } } } -- cgit v1.1