Author: jilles
Date: Wed Apr 21 21:57:03 2010
New Revision: 207021
URL: http://svn.freebsd.org/changeset/base/207021

Log:
  ln: Allow a trailing slash when creating a link to a directory.
  
  In the 'ln source... directory' synopsis, the basename of each source
  determines the name of the created link. Determine this using basename(3)
  instead of strrchr(..., '/') which is incorrect if the pathname ends in a
  slash.
  
  The patch is somewhat changed to allow for basename(3) implementations that
  change the passed pathname, and to fix the -w option's checking also.
  The code to compare directory entries only applies to hard links, which
  cannot be created to directories using ln.
  
  Example:
    ln -s /etc/defaults/ /tmp
  This should create a symlink named defaults.
  
  PR:           121568
  Submitted by: Ighighi
  MFC after:    1 week

Modified:
  head/bin/ln/ln.c

Modified: head/bin/ln/ln.c
==============================================================================
--- head/bin/ln/ln.c    Wed Apr 21 21:51:14 2010        (r207020)
+++ head/bin/ln/ln.c    Wed Apr 21 21:57:03 2010        (r207021)
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <libgen.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -226,6 +227,7 @@ linkit(const char *source, const char *t
        int ch, exists, first;
        char path[PATH_MAX];
        char wbuf[PATH_MAX];
+       char bbuf[PATH_MAX];
 
        if (!sflag) {
                /* If source doesn't exist, quit now. */
@@ -248,11 +250,9 @@ linkit(const char *source, const char *t
        if (isdir ||
            (lstat(target, &sb) == 0 && S_ISDIR(sb.st_mode)) ||
            (!hflag && stat(target, &sb) == 0 && S_ISDIR(sb.st_mode))) {
-               if ((p = strrchr(source, '/')) == NULL)
-                       p = source;
-               else
-                       ++p;
-               if (snprintf(path, sizeof(path), "%s/%s", target, p) >=
+               if (strlcpy(bbuf, source, sizeof(bbuf)) >= sizeof(bbuf) ||
+                   (p = basename(bbuf)) == NULL ||
+                   snprintf(path, sizeof(path), "%s/%s", target, p) >=
                    (ssize_t)sizeof(path)) {
                        errno = ENAMETOOLONG;
                        warn("%s", source);
@@ -276,15 +276,14 @@ linkit(const char *source, const char *t
                         * absolute path of the source, by appending `source'
                         * to the parent directory of the target.
                         */
-                       p = strrchr(target, '/');
-                       if (p != NULL)
-                               p++;
-                       else
-                               p = target;
-                       (void)snprintf(wbuf, sizeof(wbuf), "%.*s%s",
-                           (int)(p - target), target, source);
-                       if (stat(wbuf, &sb) != 0)
-                               warn("warning: %s", source);
+                       strlcpy(bbuf, target, sizeof(bbuf));
+                       p = dirname(bbuf);
+                       if (p != NULL) {
+                               (void)snprintf(wbuf, sizeof(wbuf), "%s/%s",
+                                               p, source);
+                               if (stat(wbuf, &sb) != 0)
+                                       warn("warning: %s", source);
+                       }
                }
        }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to