summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2010-04-21 21:57:03 +0000
committerjilles <jilles@FreeBSD.org>2010-04-21 21:57:03 +0000
commit1a724f1dcaab30bf93e2b9f14ba5cb859e401086 (patch)
tree9b1536d2aaea25358ac97eadee8361f3d7c641c7
parent31257c45676b6404dfd580abbffec543f3a32962 (diff)
downloadFreeBSD-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
-rw-r--r--bin/ln/ln.c27
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);
+ }
}
}
OpenPOWER on IntegriCloud