summaryrefslogtreecommitdiff
path: root/src/ln.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1993-08-27 04:43:46 +0000
committerJim Meyering <jim@meyering.net>1993-08-27 04:43:46 +0000
commit27049d3bfc5acc53cc84a91a356441746b5608d6 (patch)
tree33e5ab1dc7246a3a549f4211ff6a6673daca1d2d /src/ln.c
parent429043125e1842b92f1cdbc6c0a2772316c9d34e (diff)
downloadcoreutils-27049d3bfc5acc53cc84a91a356441746b5608d6.tar.xz
merge with 3.8.3
Diffstat (limited to 'src/ln.c')
-rw-r--r--src/ln.c58
1 files changed, 46 insertions, 12 deletions
diff --git a/src/ln.c b/src/ln.c
index 95938f533..e2ddda982 100644
--- a/src/ln.c
+++ b/src/ln.c
@@ -33,12 +33,33 @@ int link (); /* Some systems don't declare this anywhere. */
int symlink ();
#endif
+/* Construct a string NEW_DEST by concatenating DEST, a slash, and
+ basename(SOURCE) in alloca'd memory. Don't modify DEST or SOURCE. */
+
+#define PATH_BASENAME_CONCAT(new_dest, dest, source) \
+ do \
+ { \
+ char *source_base; \
+ char *tmp_source; \
+ \
+ tmp_source = (char *) alloca (strlen ((source)) + 1); \
+ strcpy (tmp_source, (source)); \
+ strip_trailing_slashes (tmp_source); \
+ source_base = basename (tmp_source); \
+ \
+ (new_dest) = (char *) alloca (strlen ((dest)) + 1 \
+ + strlen (source_base) + 1); \
+ stpcpy (stpcpy (stpcpy ((new_dest), (dest)), "/"), source_base);\
+ } \
+ while (0)
+
char *basename ();
enum backup_type get_version ();
int isdir ();
int yesno ();
void error ();
void strip_trailing_slashes ();
+char *stpcpy ();
static void usage ();
static int do_link ();
@@ -174,7 +195,30 @@ main (argc, argv)
errors = do_link (argv[optind], ".");
else if (optind == argc - 2)
{
- errors = do_link (argv[optind], argv[optind + 1]);
+ struct stat source_stats;
+ char *source;
+ char *dest;
+ char *new_dest;
+
+ source = argv[optind];
+ dest = argv[optind + 1];
+
+ /* When the destination is specified with a trailing slash and the
+ source exists but is not a directory, convert the user's command
+ `ln source dest/' to `ln source dest/basename(source)'. */
+
+ if (dest[strlen (dest) - 1] == '/'
+ && lstat (source, &source_stats) == 0
+ && !S_ISDIR (source_stats.st_mode))
+ {
+ PATH_BASENAME_CONCAT (new_dest, dest, source);
+ }
+ else
+ {
+ new_dest = dest;
+ }
+
+ errors = do_link (source, new_dest);
}
else
{
@@ -215,17 +259,7 @@ do_link (source, dest)
{
/* Target is a directory; build the full filename. */
char *new_dest;
- char *source_base;
- char *tmp_source;
-
- tmp_source = (char *) alloca (strlen (source) + 1);
- strcpy (tmp_source, source);
- strip_trailing_slashes (tmp_source);
-
- source_base = basename (tmp_source);
- new_dest = (char *)
- alloca (strlen (source_base) + 1 + strlen (dest) + 1);
- sprintf (new_dest, "%s/%s", dest, source_base);
+ PATH_BASENAME_CONCAT (new_dest, dest, source);
dest = new_dest;
}