Allow creating hard links to symlinks using ln(1).

This implements the POSIX.1-2008 -L and -P flags.

The default remains to create hard links to the target of symlinks.

Approved by:	re (kib), ed (mentor)
This commit is contained in:
Jilles Tjoelker 2009-07-19 17:35:23 +00:00
parent 3ca3047aee
commit 80a0e9b5f5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=195768
2 changed files with 41 additions and 22 deletions

View file

@ -32,7 +32,7 @@
.\" @(#)ln.1 8.2 (Berkeley) 12/30/93
.\" $FreeBSD$
.\"
.Dd June 6, 2008
.Dd July 17, 2009
.Dt LN 1
.Os
.Sh NAME
@ -41,13 +41,13 @@
.Nd link files
.Sh SYNOPSIS
.Nm
.Op Fl s Op Fl F
.Op Fl L | Fl P | Fl s Op Fl F
.Op Fl f | iw
.Op Fl hnv
.Ar source_file
.Op Ar target_file
.Nm
.Op Fl s Op Fl F
.Op Fl L | Fl P | Fl s Op Fl F
.Op Fl f | iw
.Op Fl hnv
.Ar source_file ...
@ -77,16 +77,6 @@ to a file is one of the differences between a hard and symbolic link.
.Pp
The options are as follows:
.Bl -tag -width flag
.It Fl f
If the target file already exists,
then unlink it so that the link may occur.
(The
.Fl f
option overrides any previous
.Fl i
and
.Fl w
options.)
.It Fl F
If the target file already exists and is a directory, then remove it
so that the link may occur.
@ -105,6 +95,29 @@ The
option is a no-op unless
.Fl s
option is specified.
.It Fl L
When creating a hard link to a symbolic link,
create a hard link to the target of the symbolic link.
This is the default.
This option cancels the
.Fl P
option.
.It Fl P
When creating a hard link to a symbolic link,
create a hard link to the symbolic link itself.
This option cancels the
.Fl L
option.
.It Fl f
If the target file already exists,
then unlink it so that the link may occur.
(The
.Fl f
option overrides any previous
.Fl i
and
.Fl w
options.)
.It Fl h
If the
.Ar target_file

View file

@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@ -56,12 +57,11 @@ int fflag; /* Unlink existing files. */
int Fflag; /* Remove empty directories also. */
int hflag; /* Check new name for symlink first. */
int iflag; /* Interactive mode. */
int Pflag; /* Create hard links to symlinks. */
int sflag; /* Symbolic, not hard, link. */
int vflag; /* Verbose output. */
int wflag; /* Warn if symlink target does not
* exist, and -f is not enabled. */
/* System link call. */
int (*linkf)(const char *, const char *);
char linkch;
int linkit(const char *, const char *, int);
@ -90,15 +90,20 @@ main(int argc, char *argv[])
argv += optind;
if (argc != 2)
usage();
linkf = link;
exit(linkit(argv[0], argv[1], 0));
}
while ((ch = getopt(argc, argv, "Ffhinsvw")) != -1)
while ((ch = getopt(argc, argv, "FLPfhinsvw")) != -1)
switch (ch) {
case 'F':
Fflag = 1;
break;
case 'L':
Pflag = 0;
break;
case 'P':
Pflag = 1;
break;
case 'f':
fflag = 1;
iflag = 0;
@ -129,7 +134,6 @@ main(int argc, char *argv[])
argv += optind;
argc -= optind;
linkf = sflag ? symlink : link;
linkch = sflag ? '-' : '=';
if (sflag == 0)
Fflag = 0;
@ -179,7 +183,7 @@ linkit(const char *source, const char *target, int isdir)
if (!sflag) {
/* If source doesn't exist, quit now. */
if (stat(source, &sb)) {
if ((Pflag ? lstat : stat)(source, &sb)) {
warn("%s", source);
return (1);
}
@ -276,7 +280,9 @@ linkit(const char *source, const char *target, int isdir)
}
/* Attempt the link. */
if ((*linkf)(source, target)) {
if (sflag ? symlink(source, target) :
linkat(AT_FDCWD, source, AT_FDCWD, target,
Pflag ? 0 : AT_SYMLINK_FOLLOW)) {
warn("%s", target);
return (1);
}
@ -289,8 +295,8 @@ void
usage(void)
{
(void)fprintf(stderr, "%s\n%s\n%s\n",
"usage: ln [-s [-F]] [-f | -i] [-hnv] source_file [target_file]",
" ln [-s [-F]] [-f | -i] [-hnv] source_file ... target_dir",
"usage: ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file [target_file]",
" ln [-s [-F] | -L | -P] [-f | -i] [-hnv] source_file ... target_dir",
" link source_file target_file");
exit(1);
}