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  <[EMAIL PROTECTED]>

        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;
  



_______________________________________________
Bug-hurd mailing list
[EMAIL PROTECTED]
http://mail.gnu.org/mailman/listinfo/bug-hurd

Reply via email to