📄 ln.c
字号:
if (unlink (dest) && errno != ENOENT)
{
error (0, errno, _("cannot remove %s"), quote (dest));
return 1;
}
}
else if (errno != ENOENT)
{
error (0, errno, _("accessing %s"), quote (dest));
return 1;
}
if (verbose)
{
printf ((symbolic_link
? _("create symbolic link %s to %s")
: _("create hard link %s to %s")),
quote_n (0, dest), quote_n (1, source));
if (backup_succeeded)
printf (_(" (backup: %s)"), quote (dest_backup));
putchar ('\n');
}
if ((*linkfunc) (source, dest) == 0)
{
return 0;
}
error (0, errno,
(symbolic_link
? _("creating symbolic link %s to %s")
: _("creating hard link %s to %s")),
quote_n (0, dest), quote_n (1, source));
if (dest_backup)
{
if (rename (dest_backup, dest))
error (0, errno, _("cannot un-backup %s"), quote (dest));
}
return 1;
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("\
Usage: %s [OPTION]... TARGET [LINK_NAME]\n\
or: %s [OPTION]... TARGET... DIRECTORY\n\
or: %s [OPTION]... --target-directory=DIRECTORY TARGET...\n\
"),
program_name, program_name, program_name);
fputs (_("\
Create a link to the specified TARGET with optional LINK_NAME.\n\
If LINK_NAME is omitted, a link with the same basename as the TARGET is\n\
created in the current directory. When using the second form with more\n\
than one TARGET, the last argument must be a directory; create links\n\
in DIRECTORY to each TARGET. Create hard links by default, symbolic\n\
links with --symbolic. When creating hard links, each TARGET must exist.\n\
\n\
"), stdout);
fputs (_("\
Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout);
fputs (_("\
--backup[=CONTROL] make a backup of each existing destination file\n\
-b like --backup but does not accept an argument\n\
-d, -F, --directory hard link directories (super-user only)\n\
-f, --force remove existing destination files\n\
"), stdout);
fputs (_("\
-n, --no-dereference treat destination that is a symlink to a\n\
directory as if it were a normal file\n\
-i, --interactive prompt whether to remove destinations\n\
-s, --symbolic make symbolic links instead of hard links\n\
"), stdout);
fputs (_("\
-S, --suffix=SUFFIX override the usual backup suffix\n\
--target-directory=DIRECTORY specify the DIRECTORY in which to create\n\
the links\n\
-v, --verbose print name of each file before linking\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
The version control method may be selected via the --backup option or through\n\
the VERSION_CONTROL environment variable. Here are the values:\n\
\n\
"), stdout);
fputs (_("\
none, off never make backups (even if --backup is given)\n\
numbered, t make numbered backups\n\
existing, nil numbered if numbered backups exist, simple otherwise\n\
simple, never always make simple backups\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char **argv)
{
int c;
int errors;
int make_backups = 0;
char *backup_suffix_string;
char *version_control_string = NULL;
char *target_directory = NULL;
int target_directory_specified;
unsigned int n_files;
char **file;
int dest_is_dir;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
/* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
we'll actually use backup_suffix_string. */
backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
symbolic_link = remove_existing_files = interactive = verbose
= hard_dir_link = 0;
errors = 0;
while ((c = getopt_long (argc, argv, "bdfinsvFS:V:", long_options, NULL))
!= -1)
{
switch (c)
{
case 0: /* Long-named option. */
break;
case 'V': /* FIXME: this is deprecated. Remove it in 2001. */
error (0, 0,
_("warning: --version-control (-V) is obsolete; support for\
it\nwill be removed in some future release. Use --backup=%s instead."
), optarg);
/* Fall through. */
case 'b':
make_backups = 1;
if (optarg)
version_control_string = optarg;
break;
case 'd':
case 'F':
hard_dir_link = 1;
break;
case 'f':
remove_existing_files = 1;
interactive = 0;
break;
case 'i':
remove_existing_files = 0;
interactive = 1;
break;
case 'n':
dereference_dest_dir_symlinks = 0;
break;
case 's':
#ifdef S_ISLNK
symbolic_link = 1;
#else
error (EXIT_FAILURE, 0,
_("symbolic links are not supported on this system"));
#endif
break;
case TARGET_DIRECTORY_OPTION:
target_directory = optarg;
break;
case 'v':
verbose = 1;
break;
case 'S':
make_backups = 1;
backup_suffix_string = optarg;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
break;
}
}
n_files = argc - optind;
file = argv + optind;
if (n_files == 0)
{
error (0, 0, _("missing file argument"));
usage (EXIT_FAILURE);
}
target_directory_specified = (target_directory != NULL);
if (!target_directory)
target_directory = file[n_files - 1];
/* If target directory is not specified, and there's only one
file argument, then pretend `.' was given as the second argument. */
if (!target_directory_specified && n_files == 1)
{
static char *dummy[2];
dummy[0] = file[0];
dummy[1] = ".";
file = dummy;
n_files = 2;
dest_is_dir = 1;
}
else
{
dest_is_dir = isdir (target_directory);
}
if (symbolic_link)
linkfunc = symlink;
else
linkfunc = link;
if (target_directory_specified && !dest_is_dir)
{
error (0, 0, _("%s: specified target directory is not a directory"),
quote (target_directory));
usage (EXIT_FAILURE);
}
if (backup_suffix_string)
simple_backup_suffix = xstrdup (backup_suffix_string);
backup_type = (make_backups
? xget_version (_("backup type"), version_control_string)
: none);
if (target_directory_specified || n_files > 2)
{
unsigned int i;
unsigned int last_file_idx = (target_directory_specified
? n_files - 1
: n_files - 2);
if (!target_directory_specified && !dest_is_dir)
error (EXIT_FAILURE, 0,
_("when making multiple links, last argument must be a directory"));
for (i = 0; i <= last_file_idx; ++i)
errors += do_link (file[i], target_directory);
}
else
{
struct stat source_stats;
const char *source;
char *dest;
char *new_dest;
source = file[0];
dest = file[1];
/* When the destination is specified with a trailing slash and the
source exists but is not a directory, convert the user's command
`ln source dest/' to `ln source dest/basename(source)'. */
if (dest[strlen (dest) - 1] == '/'
&& lstat (source, &source_stats) == 0
&& !S_ISDIR (source_stats.st_mode))
{
PATH_BASENAME_CONCAT (new_dest, dest, source);
}
else
{
new_dest = dest;
}
errors = do_link (source, new_dest);
}
exit (errors != 0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -