Allow hardlinks to symlinks.

Reviewed by: Bill Studenmund, Klaus Klein
This commit is contained in:
hubertf 1999-09-05 23:34:39 +00:00
parent 2425433ff6
commit abda8d9447
6 changed files with 129 additions and 7 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ln.c,v 1.15 1998/07/28 05:31:25 mycroft Exp $ */
/* $NetBSD: ln.c,v 1.16 1999/09/05 23:34:40 hubertf Exp $ */
/*
* Copyright (c) 1987, 1993, 1994
@ -43,7 +43,7 @@ __COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\n\
#if 0
static char sccsid[] = "@(#)ln.c 8.2 (Berkeley) 3/31/94";
#else
__RCSID("$NetBSD: ln.c,v 1.15 1998/07/28 05:31:25 mycroft Exp $");
__RCSID("$NetBSD: ln.c,v 1.16 1999/09/05 23:34:40 hubertf Exp $");
#endif
#endif /* not lint */
@ -137,7 +137,7 @@ linkit(target, source, isdir)
if (!sflag) {
/* If target doesn't exist, quit now. */
if (stat(target, &sb)) {
if (lstat(target, &sb)) {
warn("%s", target);
return (1);
}

View File

@ -875,6 +875,68 @@ process_copy_in ()
#ifdef CP_IFLNK
case CP_IFLNK:
{
/* Can the current symlink be linked to a previously copied
file? */
if (file_hdr.c_nlink > 1 && (archive_format == arf_newascii
|| archive_format == arf_crcascii) )
{
int link_res;
if (file_hdr.c_filesize == 0)
{
/* See CP_IFREG case for how links are handled */
defer_copyin (&file_hdr);
toss_input (in_file_des, file_hdr.c_filesize);
skip_padding (in_file_des, file_hdr.c_filesize);
break;
}
/* If the file has data (filesize != 0), then presumably
any other links have already been defer_copyin'ed(),
but GNU cpio version 2.0-2.2 didn't do that, so we
still have to check for links here (and also in case
the archive was created and later appeneded to). */
link_res = link_to_maj_min_ino (file_hdr.c_name,
file_hdr.c_dev_maj, file_hdr.c_dev_maj,
file_hdr.c_ino);
if (link_res == 0)
{
toss_input (in_file_des, file_hdr.c_filesize);
skip_padding (in_file_des, file_hdr.c_filesize);
break;
}
}
else if (file_hdr.c_nlink > 1 && archive_format != arf_tar
&& archive_format != arf_ustar)
{
int link_res;
link_res = link_to_maj_min_ino (file_hdr.c_name,
file_hdr.c_dev_maj, file_hdr.c_dev_maj,
file_hdr.c_ino);
if (link_res == 0)
{
toss_input (in_file_des, file_hdr.c_filesize);
skip_padding (in_file_des, file_hdr.c_filesize);
break;
}
}
else if ((archive_format == arf_tar || archive_format == arf_ustar)
&& file_hdr.c_tar_linkname &&
file_hdr.c_tar_linkname[0] != '\0')
{
int link_res;
link_res = link_to_maj_min_ino (file_hdr.c_tar_linkname,
file_hdr.c_dev_maj, file_hdr.c_dev_maj,
file_hdr.c_ino);
if (link_res == 0)
{
toss_input (in_file_des, file_hdr.c_filesize);
skip_padding (in_file_des, file_hdr.c_filesize);
break;
}
}
/* If not linked, copy the contents of the file. */
if (link_name == NULL)
{
if (archive_format != arf_tar && archive_format != arf_ustar)
{
@ -912,6 +974,7 @@ process_copy_in ()
free (link_name);
link_name = NULL;
}
}
break;
#endif

View File

@ -450,8 +450,9 @@ process_copy_out ()
#ifdef CP_IFLNK
case CP_IFLNK:
{
char *link_name = (char *) xmalloc (file_stat.st_size + 1);
char *link_name;
link_name = (char *) xmalloc (file_stat.st_size + 1);
if (readlink (input_name.ds_string, link_name,
file_stat.st_size) < 0)
{
@ -459,6 +460,36 @@ process_copy_out ()
free (link_name);
continue;
}
#ifndef __MSDOS__
if (archive_format == arf_tar || archive_format == arf_ustar)
{
char *otherfile;
if ((otherfile = find_inode_file (file_hdr.c_ino,
file_hdr.c_dev_maj,
file_hdr.c_dev_min)))
{
file_hdr.c_mode = CP_IFREG; /* XXX hardlink! */
file_hdr.c_tar_linkname = otherfile;
write_out_header (&file_hdr, out_file_des);
break;
}
}
if ( (archive_format == arf_newascii || archive_format == arf_crcascii)
&& (file_hdr.c_nlink > 1) )
{
if (last_link (&file_hdr) )
{
writeout_other_defers (&file_hdr, out_file_des);
}
else
{
add_link_defer (&file_hdr);
break;
}
}
#endif
if (archive_format == arf_tar || archive_format == arf_ustar)
{
if (file_stat.st_size + 1 > 100)
@ -479,6 +510,12 @@ process_copy_out ()
copy_buf_out (link_name, out_file_des, file_stat.st_size);
pad_output (out_file_des, file_hdr.c_filesize);
}
#ifndef __MSDOS__
if (archive_format == arf_tar || archive_format == arf_ustar)
add_inode (file_hdr.c_ino, input_name.ds_string, file_hdr.c_dev_maj,
file_hdr.c_dev_min);
#endif
free (link_name);
}
break;

View File

@ -332,6 +332,24 @@ process_copy_pass ()
}
link_name[in_file_stat.st_size] = '\0';
/* Can the current symlink be linked to a another file?
Set link_name to the original file name. */
if (link_flag)
/* User said to link it if possible. Try and link to
the original copy. If that fails we'll still try
and link to a copy we've already made. */
link_res = link_to_name (output_name.ds_string,
input_name.ds_string);
if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
link_res = link_to_maj_min_ino (output_name.ds_string,
major (in_file_stat.st_dev),
minor (in_file_stat.st_dev),
in_file_stat.st_ino);
/* If the link was not (hard)linked, make a softlink. */
if (link_res < 0)
{
res = UMASKED_SYMLINK (link_name, output_name.ds_string,
in_file_stat.st_mode);
if (res < 0 && create_dir_flag)
@ -356,6 +374,7 @@ process_copy_pass ()
error (0, errno, "%s", output_name.ds_string);
free (link_name);
}
}
#endif
else
{

View File

@ -18,7 +18,7 @@ along with GNU Tar; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef lint
static char rcsid[] = "$Id: create.c,v 1.7 1998/06/07 02:30:12 enami Exp $";
static char rcsid[] = "$Id: create.c,v 1.8 1999/09/05 23:34:40 hubertf Exp $";
#endif /* not lint */
/*
@ -292,6 +292,9 @@ dump_file (p, curdev, toplevel)
#endif
#ifdef S_ISFIFO
|| S_ISFIFO (hstat.st_mode)
#endif
#ifdef S_ISLNK
|| S_ISLNK (hstat.st_mode)
#endif
))
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_syscalls.c,v 1.146 1999/07/31 03:18:43 christos Exp $ */
/* $NetBSD: vfs_syscalls.c,v 1.147 1999/09/05 23:34:39 hubertf Exp $ */
/*
* Copyright (c) 1989, 1993
@ -1391,7 +1391,7 @@ sys_link(p, v, retval)
struct nameidata nd;
int error;
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;