[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
New option for ln, firmlinks!
From: |
Alfred M. Szmidt |
Subject: |
New option for ln, firmlinks! |
Date: |
Sat, 24 Jan 2004 18:51:53 +0100 (MET) |
Howdy,
The following hack implements the --firm/-m option for ln so that it
will create firm links. Now, most GNU/Linux people won't be familiar
with the concept, and I'm not really sure how to explain it either.
The best example I can think of that explains the difference between
symlinks and firmlinks is the following:
hurd:/home/ams/coreutils/coreutils/src# ./ln -s /ams/foo symlink
hurd:/home/ams/coreutils/coreutils/src# ./ln -m /ams/foo firmlink
hurd:/home/ams/coreutils/coreutils/src# cd symlink
hurd:/home/ams/coreutils/coreutils/src/symlink# ls ..
foo hurd.obj lost+found oskit.obj sub-hurd
hurd:/home/ams/coreutils/coreutils/src/symlink# cd ../firmlink
hurd:/home/ams/coreutils/coreutils/src/firmlink# ls ..
CVS
Makefile
Makefile.am
[..snip...]
hurd:/home/ams/coreutils/coreutils/src/firmlink# ls
hurd:/home/ams/coreutils/coreutils/src/firmlink# ls /ams/foo
hurd:/home/ams/coreutils/coreutils/src/firmlink# touch foo
hurd:/home/ams/coreutils/coreutils/src/firmlink# ls -l
total 0
-rw-r--r-- 1 root root 0 Jan 25 02:48 foo
hurd:/home/ams/coreutils/coreutils/src/firmlink# ls -l /ams/foo
total 0
-rw-r--r-- 1 root root 0 Jan 25 02:48 foo
hurd:/home/ams/coreutils/coreutils/src/firmlink#
As you see, a firmlink is more or less a "real" link, and doesn't
exhibit the sometimes awkward behaviour of symbolic links (`ls ..' is
one such example).
Note that I didn't bother in creating a NEWS entry, or updating the
manual. This is mostly a hack that I just wanted to share and get
some comments about. For example, firmlink() should be moved into
libc, _HURD_FIRMLINK should be defined in <hurd/paths.h>, propor
autoconf checks should be created so that ln will compile on system
that don't support firmlinks, etc.
2004-01-24 Alfred M. Szmidt <ams@kemisten.nu>
Added new option for `ln', --firm.
* src/ln.c (firm_link): New variable.
(long_options): Support new option `--firm'.
(_HURD_FIRMLINK): New macro.
(hurd_fail, firmlink): New functions.
(do_link, usage, main): Support new option `--firm'.
(do_link): Allow the creation of firmlinks for directories.
*** src/ln.c.~1.132.~ Sat Oct 18 03:05:47 2003
--- src/ln.c Sun Jan 25 02:32:05 2004
***************
*** 96,107 ****
enum backup_type backup_type;
/* A pointer to the function used to make links. This will point to either
! `link' or `symlink'. */
static int (*linkfunc) ();
/* If nonzero, make symbolic links; otherwise, make hard links. */
static int symbolic_link;
/* If nonzero, ask the user before removing existing files. */
static int interactive;
--- 96,110 ----
enum backup_type backup_type;
/* A pointer to the function used to make links. This will point to either
! `link', `symlink' or `firmlink'. */
static int (*linkfunc) ();
/* If nonzero, make symbolic links; otherwise, make hard links. */
static int symbolic_link;
+ /* If nonzero, make firm links; otherwise make hard links. */
+ static int firm_link;
+
/* If nonzero, ask the user before removing existing files. */
static int interactive;
***************
*** 133,138 ****
--- 136,142 ----
{"suffix", required_argument, NULL, 'S'},
{"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION},
{"symbolic", no_argument, NULL, 's'},
+ {"firm", no_argument, NULL, 'm'},
{"verbose", no_argument, NULL, 'v'},
{"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */
{GETOPT_HELP_OPTION_DECL},
***************
*** 140,145 ****
--- 144,234 ----
{NULL, 0, NULL, 0}
};
+ /* Snatched from glibc; and modified for firm links and some sort of
+ stand-aloneness. Should really be moved back into libc as a real
+ call. */
+
+ #include <string.h>
+ #include <unistd.h>
+ #include <hurd.h>
+ #include <hurd/paths.h>
+ #include <fcntl.h>
+
+ #define _HURD_FIRMLINK _HURD "firmlink"
+
+ int
+ hurd_fail (error_t err)
+ {
+ switch (err)
+ {
+ case EMACH_SEND_INVALID_DEST:
+ case EMIG_SERVER_DIED:
+ /* The server has disappeared! */
+ err = EIEIO;
+ break;
+
+ case KERN_NO_SPACE:
+ err = ENOMEM;
+ break;
+
+ case KERN_INVALID_ARGUMENT:
+ err = EINVAL;
+ break;
+
+ case 0:
+ return 0;
+
+ default:
+ break;
+ }
+
+ errno = err;
+ return -1;
+ }
+
+ int
+ firmlink (const char *from, const char *to)
+ {
+ error_t err;
+ file_t dir, node;
+ char *name;
+ const size_t len = strlen (from) + 1;
+ char buf[sizeof (_HURD_FIRMLINK) + len];
+ mode_t umask = getumask ();
+
+ /* A firmlink is a file whose translator is "/hurd/firmlink\0target\0". */
+
+ memcpy (buf, _HURD_FIRMLINK, sizeof (_HURD_FIRMLINK));
+ memcpy (&buf[sizeof (_HURD_FIRMLINK)], from, len);
+
+ dir = file_name_split (to, &name);
+ if (dir == MACH_PORT_NULL)
+ return -1;
+
+ /* Create a new, unlinked node in the target directory. */
+ err = dir_mkfile (dir, O_WRITE, 0777 & ~umask, &node);
+
+ if (! err)
+ /* Set the node's translator to make it a firmlink. */
+ err = file_set_translator (node,
+ FS_TRANS_EXCL|FS_TRANS_SET,
+ FS_TRANS_EXCL|FS_TRANS_SET, 0,
+ buf, sizeof (_HURD_FIRMLINK) + len,
+ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
+
+ if (! err)
+ /* Link the node, now a valid link, into the target directory. */
+ err = dir_link (dir, node, name, 1);
+
+ mach_port_deallocate (mach_task_self (), dir);
+ mach_port_deallocate (mach_task_self (), node);
+
+ if (err)
+ return hurd_fail (err);
+ return 0;
+ }
+
+
/* Make a link DEST to the (usually) existing file SOURCE.
Symbolic links to nonexistent files are allowed.
If DEST is a directory, put the link to SOURCE in that directory.
***************
*** 174,180 ****
quote (source));
}
! if (!hard_dir_link && S_ISDIR (source_stats.st_mode))
{
error (0, 0, _("%s: hard link not allowed for directory"),
quote (source));
--- 263,269 ----
quote (source));
}
! if (!firm_link && !hard_dir_link && S_ISDIR (source_stats.st_mode))
{
error (0, 0, _("%s: hard link not allowed for directory"),
quote (source));
***************
*** 306,331 ****
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))
--- 395,432 ----
if (verbose)
{
! if (symbolic_link)
! printf (_("create symbolic link %s to %s"),
! quote_n (0, dest), quote_n (1, source));
! else if (firm_link)
! printf (_("create firm link %s to %s"),
! quote_n (0, dest), quote_n (1, source));
! else
! printf (_("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;
}
!
! if (symbolic_link)
! error (0, errno,
! _("creating symbolic link %s to %s"),
! quote_n (0, dest), quote_n (1, source));
! else if (firm_link)
! error (0, errno,
! _("creating firm link %s to %s"),
! quote_n (0, dest), quote_n (1, source));
! else
! error (0, errno,
! _("creating hard link %s to %s"),
! quote_n (0, dest), quote_n (1, source));
!
if (dest_backup)
{
if (rename (dest_backup, dest))
***************
*** 354,360 ****
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 (_("\
--- 455,462 ----
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 and firm links with --firm. When creating hard\n\
! links, each TARGET must exist.\n\
\n\
"), stdout);
fputs (_("\
***************
*** 375,380 ****
--- 477,485 ----
-s, --symbolic make symbolic links instead of hard links\n\
"), stdout);
fputs (_("\
+ -m, --firm make firm 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\
***************
*** 430,436 ****
= hard_dir_link = 0;
errors = 0;
! while ((c = getopt_long (argc, argv, "bdfinsvFS:V:", long_options, NULL))
!= -1)
{
switch (c)
--- 535,541 ----
= hard_dir_link = 0;
errors = 0;
! while ((c = getopt_long (argc, argv, "bdfinmsvFS:V:", long_options, NULL))
!= -1)
{
switch (c)
***************
*** 473,478 ****
--- 578,591 ----
_("symbolic links are not supported on this system"));
#endif
break;
+ case 'm':
+ #if 1
+ firm_link = 1;
+ #else
+ error (EXIT_FAILURE, 0,
+ _("firm links are not supported on this system"));
+ #endif
+ break;
case TARGET_DIRECTORY_OPTION:
target_directory = optarg;
break;
***************
*** 522,527 ****
--- 635,642 ----
if (symbolic_link)
linkfunc = symlink;
+ else if (firm_link)
+ linkfunc = firmlink;
else
linkfunc = link;
- New option for ln, firmlinks!,
Alfred M. Szmidt <=
- Re: New option for ln, firmlinks!, Andreas Schwab, 2004/01/24
- Re: New option for ln, firmlinks!, Alfred M. Szmidt, 2004/01/24
- Re: New option for ln, firmlinks!, Andreas Schwab, 2004/01/24
- Re: New option for ln, firmlinks!, Alfred M. Szmidt, 2004/01/24
- Re: New option for ln, firmlinks!, Andreas Schwab, 2004/01/24
- Re: New option for ln, firmlinks!, Alfred M. Szmidt, 2004/01/24
- Re: New option for ln, firmlinks!, Andreas Schwab, 2004/01/24
- Re: New option for ln, firmlinks!, Alfred M. Szmidt, 2004/01/24
- Re: New option for ln, firmlinks!, Andreas Schwab, 2004/01/24
- Re: New option for ln, firmlinks!, Alfred M. Szmidt, 2004/01/24