busybox/coreutils/ln.c
Eric Andersen 0b4551faf5 From Matt Kraai <kraai@alumni.carnegiemellon.edu>:
Howdy,

Bug #1006 reports that

ln -s /tmp/foo .

does not work correctly.  In fact, it appears that any instantiation of

ln -s FILE... DIRECTORY

does not work.  The following patch adds support for this form, which
then fixes the particular instance noted in the bug report.

In the process, I needed the basename function.  This appears in the
string.h provided by glibc, but not uC-libc.  So I wrote my own to go in
utility.c, called get_last_path_component.  I also modified the basename
utility to use this function.

At some point it might be desirous to use the basename from the library
if it exists, and otherwise compile our own.  But I don't know how to do
this.

Matt
2000-07-10 16:44:03 +00:00

173 lines
3.8 KiB
C

/* vi: set sw=4 ts=4: */
/*
* Mini ln implementation for busybox
*
* Copyright (C) 1999,2000 by Lineo, inc.
* Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "internal.h"
#define BB_DECLARE_EXTERN
#define bb_need_name_too_long
#define bb_need_not_a_directory
#include "messages.c"
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
static const char ln_usage[] =
"ln [OPTION] TARGET... LINK_NAME|DIRECTORY\n"
#ifndef BB_FEATURE_TRIVIAL_HELP
"\nCreate a link named LINK_NAME or DIRECTORY to the specified TARGET\n"
"\nYou may use '--' to indicate that all following arguments are non-options.\n\n"
"Options:\n"
"\t-s\tmake symbolic links instead of hard links\n"
"\t-f\tremove existing destination files\n"
#if 0
"\t-n\tno dereference symlinks - treat like normal file\n"
#endif
#endif
;
static int symlinkFlag = FALSE;
static int removeoldFlag = FALSE;
static int followLinks = TRUE;
extern int ln_main(int argc, char **argv)
{
char *linkName, *dirName;
int linkIntoDirFlag;
int stopIt = FALSE;
argc--;
argv++;
/* Parse any options */
while (argc > 0 && stopIt == FALSE) {
if (**argv == '-') {
while (*++(*argv))
switch (**argv) {
case 's':
symlinkFlag = TRUE;
break;
case 'f':
removeoldFlag = TRUE;
break;
case 'n':
followLinks = FALSE;
break;
case '-':
stopIt = TRUE;
break;
default:
usage(ln_usage);
}
argc--;
argv++;
}
else
break;
}
if (argc < 2) {
usage(ln_usage);
}
linkName = argv[argc - 1];
if (strlen(linkName) > BUFSIZ) {
fprintf(stderr, name_too_long, "ln");
exit FALSE;
}
linkIntoDirFlag = isDirectory(linkName, TRUE, NULL);
if ((argc >= 3) && linkIntoDirFlag == FALSE) {
fprintf(stderr, not_a_directory, "ln", linkName);
exit FALSE;
}
if (linkIntoDirFlag == TRUE)
dirName = linkName;
while (argc-- >= 2) {
#if 0
char srcName[BUFSIZ + 1];
int nChars;
#endif
int status;
if (strlen(*argv) > BUFSIZ) {
fprintf(stderr, name_too_long, "ln");
exit FALSE;
}
#if 0
if (followLinks == FALSE) {
strcpy(srcName, *argv);
} else {
/* Warning! This can silently truncate if > BUFSIZ, but
I don't think that there can be one > BUFSIZ anyway. */
nChars = readlink(*argv, srcName, BUFSIZ);
srcName[nChars] = '\0';
}
#endif
if (linkIntoDirFlag == TRUE) {
char *baseName = get_last_path_component(*argv);
linkName = (char *)malloc(strlen(dirName)+strlen(baseName)+2);
strcpy(linkName, dirName);
if(dirName[strlen(dirName)-1] != '/')
strcat(linkName, "/");
strcat(linkName,baseName);
}
if (removeoldFlag == TRUE) {
status = (unlink(linkName) && errno != ENOENT);
if (status != 0) {
perror(linkName);
exit FALSE;
}
}
if (symlinkFlag == TRUE)
status = symlink(*argv, linkName);
else
status = link(*argv, linkName);
if (status != 0) {
perror(linkName);
exit FALSE;
}
if (linkIntoDirFlag)
free(linkName);
argv++;
}
return( TRUE);
}
/*
Local Variables:
c-file-style: "linux"
c-basic-offset: 4
tab-width: 4
End:
*/