>From 0d0c745f4c5dd2c346b15fc0ac597986ce2b2b42 Mon Sep 17 00:00:00 2001 From: Julien Thomas Date: Mon, 27 May 2013 17:52:52 +0200 Subject: [PATCH 3/3] ln: Implement -n option as in corutils ln This option treats destination that is a symlink to a directory as if it was a normal file. It allows ln -snf ... calls as doable with coreutils ln. The option is only available if HAVE_LSTAT is defined as it's the way the original builtin was implemented. --- ln.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/ln.c b/ln.c index 63bd38c..386f32f 100644 --- a/ln.c +++ b/ln.c @@ -46,6 +46,7 @@ typedef int unix_link_syscall_t __P((const char *, const char *)); #define LN_SYMLINK 0x01 #define LN_UNLINK 0x02 +#define LN_NO_DEREF_DDIR_SYM 0x04 static unix_link_syscall_t *linkfn; static int dolink (); @@ -61,7 +62,11 @@ ln_builtin (list) flags = 0; reset_internal_getopt (); +#if defined (HAVE_LSTAT) + while ((opt = internal_getopt (list, "fsn")) != -1) +#else while ((opt = internal_getopt (list, "fs")) != -1) +#endif { switch (opt) { @@ -71,6 +76,11 @@ ln_builtin (list) case 's': flags |= LN_SYMLINK; break; +#if defined (HAVE_LSTAT) + case 'n': + flags |= LN_NO_DEREF_DDIR_SYM; + break; +#endif default: builtin_usage (); return (EX_USAGE); @@ -139,8 +149,10 @@ mkdirpath (dir, file) #if defined (HAVE_LSTAT) # define LSTAT lstat +# define LSTAT_OR_STAT_IF(c, f, b) ((c) ? lstat((f), (b)) : stat((f), (b))) #else # define LSTAT stat +# define LSTAT_OR_STAT_IF(c, f, b) (stat((f), (b))) #endif static int @@ -172,7 +184,8 @@ dolink (src, dst, flags) /* If the destination is a directory, create the final filename by appending the basename of the source to the destination. */ dst_path = 0; - if ((stat (dst, &dsb) == 0) && S_ISDIR (dsb.st_mode)) + if ((LSTAT_OR_STAT_IF(flags & LN_NO_DEREF_DDIR_SYM, dst, &dsb) == 0) && + (S_ISDIR (dsb.st_mode)) != 0) { if ((p = strrchr (src, '/')) == 0) p = src; @@ -206,13 +219,17 @@ dolink (src, dst, flags) } char *ln_doc[] = { - "Link files.", - "", - "Create a new directory entry with the same modes as the original", - "file. The -f option means to unlink any existing file, permitting", - "the link to occur. The -s option means to create a symbolic link.", - "By default, ln makes hard links.", - (char *)NULL + "Link files.", + "", + "Create a new directory entry with the same modes as the original file.", + "Available options:", + " -f Unlink any existing file, permitting the link to occur.", + " -s Create a symbolic link (by default, ln makes hard links).", +#if defined (HAVE_LSTAT) + " -n Treat destination that is a symlink to a directory as if it", + " were a normal file.", +#endif + (char *)NULL }; /* The standard structure describing a builtin command. bash keeps an array @@ -223,6 +240,10 @@ struct builtin ln_struct = { BUILTIN_ENABLED, /* initial flags for builtin */ ln_doc, /* array of long documentation strings. */ /* usage synopsis; becomes short_doc */ +#if defined (HAVE_LSTAT) + "ln [-fsn] file1 [file2] OR ln [-fsn] file ... directory", +#else "ln [-fs] file1 [file2] OR ln [-fs] file ... directory", +#endif 0 /* reserved for internal use */ }; -- 1.7.10.4