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
This commit is contained in:
parent
3acd904d85
commit
dc00aa5dd6
23
bin/ln/ln.c
23
bin/ln/ln.c
@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <libgen.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -226,6 +227,7 @@ linkit(const char *source, const char *target, int isdir)
|
|||||||
int ch, exists, first;
|
int ch, exists, first;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
char wbuf[PATH_MAX];
|
char wbuf[PATH_MAX];
|
||||||
|
char bbuf[PATH_MAX];
|
||||||
|
|
||||||
if (!sflag) {
|
if (!sflag) {
|
||||||
/* If source doesn't exist, quit now. */
|
/* If source doesn't exist, quit now. */
|
||||||
@ -248,11 +250,9 @@ linkit(const char *source, const char *target, int isdir)
|
|||||||
if (isdir ||
|
if (isdir ||
|
||||||
(lstat(target, &sb) == 0 && S_ISDIR(sb.st_mode)) ||
|
(lstat(target, &sb) == 0 && S_ISDIR(sb.st_mode)) ||
|
||||||
(!hflag && stat(target, &sb) == 0 && S_ISDIR(sb.st_mode))) {
|
(!hflag && stat(target, &sb) == 0 && S_ISDIR(sb.st_mode))) {
|
||||||
if ((p = strrchr(source, '/')) == NULL)
|
if (strlcpy(bbuf, source, sizeof(bbuf)) >= sizeof(bbuf) ||
|
||||||
p = source;
|
(p = basename(bbuf)) == NULL ||
|
||||||
else
|
snprintf(path, sizeof(path), "%s/%s", target, p) >=
|
||||||
++p;
|
|
||||||
if (snprintf(path, sizeof(path), "%s/%s", target, p) >=
|
|
||||||
(ssize_t)sizeof(path)) {
|
(ssize_t)sizeof(path)) {
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
warn("%s", source);
|
warn("%s", source);
|
||||||
@ -276,17 +276,16 @@ linkit(const char *source, const char *target, int isdir)
|
|||||||
* absolute path of the source, by appending `source'
|
* absolute path of the source, by appending `source'
|
||||||
* to the parent directory of the target.
|
* to the parent directory of the target.
|
||||||
*/
|
*/
|
||||||
p = strrchr(target, '/');
|
strlcpy(bbuf, target, sizeof(bbuf));
|
||||||
if (p != NULL)
|
p = dirname(bbuf);
|
||||||
p++;
|
if (p != NULL) {
|
||||||
else
|
(void)snprintf(wbuf, sizeof(wbuf), "%s/%s",
|
||||||
p = target;
|
p, source);
|
||||||
(void)snprintf(wbuf, sizeof(wbuf), "%.*s%s",
|
|
||||||
(int)(p - target), target, source);
|
|
||||||
if (stat(wbuf, &sb) != 0)
|
if (stat(wbuf, &sb) != 0)
|
||||||
warn("warning: %s", source);
|
warn("warning: %s", source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the file exists, first check it is not the same directory entry.
|
* If the file exists, first check it is not the same directory entry.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user