bug-fileutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

--absolute and --relative option for ln(1).


From: Shigio Yamaguchi
Subject: --absolute and --relative option for ln(1).
Date: Fri, 29 Mar 2002 13:24:11 +0900

Hello,

I have implemented two options for ln(1).

[Problem]

The ln(1) makes a wrong symbolic link in some cases.
(It is not a bug but a spec of ln(1).)

For example:

        % cd /usr
        % ln -s src/bin /tmp/bin
        % cd /tmp/bin
        /tmp/bin: No such file or directory.
        % ls -l /tmp/bin
        lrwxrwxrwx  1 shigio  wheel  7 Jan 10 22:10 /tmp/bin -> src/bin
                                                                ~~~~~~~
                                                                It's wrong!

[Solution]

I have made a patch for ln(1) to make right symbolic links.
New ln(1) has additional two options:

   -a(--absolute)  If the -s option is specified, make absolute symbolic link.
   -r(--relative)  If the -s option is specified, make relative symbolic link.

   The -a and -r options override each other; the last one specified
   determines the method used.

New ln(1) with -r or -a option makes right symbolic link like this:

        % cd /usr
        % ln -sr src/bin /tmp/bin       # relative symbolic link
        % cd /tmp/bin
        lrwxrwxrwx  1 shigio  wheel  14 Jan 10 22:12 /tmp/bin -> ../usr/src/bin
                                                                 ~~~~~~~~~~~~~~
                                                                 Right!

        or

        % cd /usr
        % ln -sa src/bin /tmp/bin       # absolute symbolic link
        % cd /tmp/bin
        lrwxrwxrwx  1 shigio  wheel  12 Jan 10 22:13 /tmp/bin -> /usr/src/bin
                                                                 ~~~~~~~~~~~~
                                                                 Right!

[Files]

Here is a patch for fileutils-4.1.7.

This patch calls two external functions: abs2rel() and rel2abs().
You can get the source code from http://www.tamacom.com/pathconvert/.

If you include this patch, abs2rel and rel2abs into fileutils,
I will transfer all of them to FSF and write a disclaimer paper for it.

Thanks!

/*
 * This file is placed into the public domain by the author,
 * Shigio Yamaguchi <address@hidden>
 */
diff -c -r -N fileutils-4.1.7-/man/ln.1 fileutils-4.1.7/man/ln.1
*** fileutils-4.1.7-/man/ln.1   Fri Mar 29 12:49:23 2002
--- fileutils-4.1.7/man/ln.1    Fri Mar 29 12:56:18 2002
***************
*** 20,28 ****
--- 20,32 ----
  than one TARGET, the last argument must be a directory;  create links
  in DIRECTORY to each TARGET.  Create hard links by default, symbolic
  links with \fB\-\-symbolic\fR.  When creating hard links, each TARGET must 
exist.
+ The \fB\-\-absolute\fR and \fB\-\-relative\fR options override each other; 
the last one specified determines
  .PP
  Mandatory arguments to long options are mandatory for short options too.
  .TP
+ \fB\-a\fR, \fB\-\-absolute\fR
+ If \fB\-\-symbolic\fR option is specified, make absolute symbolic link.
+ .TP
  \fB\-\-backup\fR[=\fICONTROL\fR]
  make a backup of each existing destination file
  .TP
***************
*** 41,46 ****
--- 45,53 ----
  .TP
  \fB\-i\fR, \fB\-\-interactive\fR
  prompt whether to remove destinations
+ .TP
+ \fB\-r\fR, \fB\-\-relative\fR
+ If \fB\-\-symbolic\fR option is specified, make relative symbolic link.
  .TP
  \fB\-s\fR, \fB\-\-symbolic\fR
  make symbolic links instead of hard links
diff -c -r -N fileutils-4.1.7-/src/ln.c fileutils-4.1.7/src/ln.c
*** fileutils-4.1.7-/src/ln.c   Fri Mar 29 12:49:21 2002
--- fileutils-4.1.7/src/ln.c    Fri Mar 29 12:24:48 2002
***************
*** 119,131 ****
--- 119,139 ----
     symlink-to-dir before creating the new link.  */
  static int dereference_dest_dir_symlinks = 1;
  
+ /* If nonzero, make absolute symbolic links. */
+ static int absolute = 0;
+ 
+ /* If nonzero, make relative symbolic links. */
+ static int relative = 0;
+ 
  static struct option const long_options[] =
  {
+   {"absolute", no_argument, NULL, 'a'},
    {"backup", optional_argument, NULL, 'b'},
    {"directory", no_argument, NULL, 'F'},
    {"no-dereference", no_argument, NULL, 'n'},
    {"force", no_argument, NULL, 'f'},
    {"interactive", no_argument, NULL, 'i'},
+   {"relative", no_argument, NULL, 'r'},
    {"suffix", required_argument, NULL, 'S'},
    {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION},
    {"symbolic", no_argument, NULL, 's'},
***************
*** 149,154 ****
--- 157,165 ----
    char *dest_backup = NULL;
    int lstat_status;
    int backup_succeeded = 0;
+   char base[PATH_MAX];
+   char abssource[PATH_MAX];
+   char relsource[PATH_MAX];
  
    /* Use stat here instead of lstat.
       On SVR4, link does not follow symlinks, so this check disallows
***************
*** 212,217 ****
--- 223,264 ----
        }
      }
  
+   /* If -a or -r option specified, do path conversion. */
+   if (symbolic_link && (absolute || relative))
+     {
+         /* convert source directory into absolute name */
+         if (*source != '/') {
+             if (getcwd(base, PATH_MAX) == NULL)
+                 error(1, errno, "couldn't get current directory.");
+             if (rel2abs(source, base, abssource, PATH_MAX) == NULL)
+                 error(1, errno, "couldn't convert path");
+             source = abssource;
+         }
+         /* convert source directory into relative name */
+         if (relative) {
+             char path[PATH_MAX];
+             const char *p;
+ 
+             if (!S_ISDIR (dest_stats.st_mode)) {
+                 if ((p = strrchr(dest, '/')) != NULL) {
+                     int col = p - dest + 1;
+                     strncpy(path, dest, col);
+                     path[col] = 0;
+                 } else {
+                     path[0] = '.';
+                     path[1] = 0;
+                 }
+                 p = path;
+             } else
+                 p = dest;
+             if (realpath(p, base) == NULL)
+                 error(1, errno, p);
+             if (abs2rel(source, base, relsource, PATH_MAX) == NULL)
+                 error(1, errno, "couldn't convert path");
+             source = relsource;
+         }
+     }
+ 
    /* If --force (-f) has been specified without --backup, then before
       making a link ln must remove the destination file if it exists.
       (with --backup, it just renames any existing destination file)
***************
*** 355,360 ****
--- 402,408 ----
  Mandatory arguments to long options are mandatory for short options too.\n\
  "), stdout);
        fputs (_("\
+   -a, --absolute              make absolute symbolic link\n\
        --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\
***************
*** 363,368 ****
--- 411,417 ----
        fputs (_("\
    -n, --no-dereference        treat destination that is a symlink to a\n\
                                  directory as if it were a normal file\n\
+   -r, --relative              make relative symbolic link\n\
    -i, --interactive           prompt whether to remove destinations\n\
    -s, --symbolic              make symbolic links instead of hard links\n\
  "), stdout);
***************
*** 421,427 ****
      = hard_dir_link = 0;
    errors = 0;
  
!   while ((c = getopt_long (argc, argv, "bdfinsvFS:V:", long_options, NULL))
         != -1)
      {
        switch (c)
--- 470,476 ----
      = hard_dir_link = 0;
    errors = 0;
  
!   while ((c = getopt_long (argc, argv, "abdfinrsvFS:V:", long_options, NULL))
         != -1)
      {
        switch (c)
***************
*** 436,441 ****
--- 485,493 ----
                   ), optarg);
          /* Fall through.  */
  
+       case 'a':
+         absolute = 1;
+         break;
        case 'b':
          make_backups = 1;
          if (optarg)
***************
*** 455,460 ****
--- 507,515 ----
          break;
        case 'n':
          dereference_dest_dir_symlinks = 0;
+         break;
+       case 'r':
+         relative = 1;
          break;
        case 's':
  #ifdef S_ISLNK
--
Shigio Yamaguchi - Tama Communications Corporation




reply via email to

[Prev in Thread] Current Thread [Next in Thread]