Message-ID: <39941478.329CA50B@softhome.net> Date: Fri, 11 Aug 2000 16:58:00 +0200 From: Laurynas Biveinis X-Mailer: Mozilla 4.74 [en] (Win98; U) X-Accept-Language: lt,en MIME-Version: 1.0 To: DJGPP Workers Subject: Patch: symlink() Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Reply-To: djgpp-workers AT delorie DOT com This one replaces old symlink() with new one. The diff itself isn't very clean: there are mixed SRC += *.c entries in Makefiles in this and previous __solve_symlinks() patch, but IMHO it's not very big problem. (Given that I checkin both patches at once). Feedback appreciated, Laurynas Index: djgpp/src/docs/kb/wc204.txi =================================================================== RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v retrieving revision 1.17 diff -u -r1.17 wc204.txi --- wc204.txi 2000/08/11 11:16:19 1.17 +++ wc204.txi 2000/08/11 14:51:33 @@ -95,7 +95,14 @@ UNIX-style symbolic links are fully emulated by library. As a part of this, new functions @code{__solve_symlinks} and @code{readlink} have been added to library. + +@findex symlink AT r{, and symlink support} +As a part of symlink emulation, @code{symlink} no longer emulates symlinks +to executables by creating stubs. It creates symlinks to all files instead. Index: djgpp/src/libc/compat/unistd/makefile =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/compat/unistd/makefile,v retrieving revision 1.5 diff -u -r1.5 makefile --- makefile 2000/08/11 11:16:23 1.5 +++ makefile 2000/08/11 14:51:38 @@ -14,9 +14,11 @@ SRC += llseek.c SRC += nice.c SRC += readlink.c +SRC += symlink.c SRC += sync.c SRC += truncate.c SRC += usleep.c SRC += vfork.c +SRC += xsymlink.c include $(TOP)/../makefile.inc Index: djgpp/src/libc/compat/unistd/symlink.c =================================================================== RCS file: symlink.c diff -N symlink.c --- /dev/null Tue May 5 16:32:27 1998 +++ symlink.c Fri Aug 11 10:51:38 2000 @@ -0,0 +1,53 @@ +/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */ +/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ +/* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ +#include +#include +#include +#include +#include +#include + +#include "xsymlink.h" + +/* Emulate symlinks for all files */ +int symlink(const char *source, const char *dest) +{ + int symlink_file; + char real_dest[FILENAME_MAX]; + static char fill_buf[_SYMLINK_FILE_LEN + 1] = + "This is just a text to force symlink file to " + "be 510 bytes long. Do not delete it nor spaces " + "following it."; + memset(fill_buf + strlen(fill_buf), ' ', + _SYMLINK_FILE_LEN - strlen(fill_buf)); + + /* Common error conditions */ + if (!source || !dest) + { + errno = EINVAL; + return -1; + } + + /* The ``dest'' may have symlinks somewhere in the path itself. */ + if (!__solve_symlinks(dest, real_dest)) + return -1; /* Errno (ELOOP) from __solve_symlinks() call. */ + + /* Check if there already is file with symlink's name */ + if (__file_exists(real_dest)) + { + errno = EEXIST; + return -1; + } + + symlink_file = _creat(real_dest, 0); + if (symlink_file < 0) + return -1; /* Return errno from creat() call */ + write(symlink_file, _SYMLINK_PREFIX, _SYMLINK_PREFIX_LEN); + write(symlink_file, source, strlen(source)); + write(symlink_file, "\n", 1); + write(symlink_file, fill_buf, _SYMLINK_FILE_LEN - _SYMLINK_PREFIX_LEN - strlen(source) - 1); + _close(symlink_file); + + return 0; +} Index: djgpp/src/libc/compat/unistd/symlink.txh =================================================================== RCS file: symlink.txh diff -N symlink.txh --- /dev/null Tue May 5 16:32:27 1998 +++ symlink.txh Fri Aug 11 10:51:38 2000 @@ -0,0 +1,32 @@ +@node symlink, io +@subheading Syntax + +@example +#include + +int symlink(const char *exists, const char *new); +@end example + +@subheading Description +DOS does not support symbolic links. However, DJGPP emulates them--- +this function creates a file with special size and format, so other +DJGPP library functions transparently work with file which is pointed to +by symlink. Of course, it does not work outside DJGPP programs. Those +library functions which are simple wrappers about DOS calls do not +use symlinks neither. + +@subheading Return Value + +Zero in case of success, -1 in case of failure (and @code{errno} set to +the appropriate error code). + +@subheading Portability + +@portability !ansi, !posix + +@subheading Example + +@example +symlink ("c:/djgpp/bin/grep", "c:/djgpp/bin/fgrep"); +@end example + Index: djgpp/src/libc/posix/unistd/makefile =================================================================== RCS file: /cvs/djgpp/djgpp/src/libc/posix/unistd/makefile,v retrieving revision 1.3 diff -u -r1.3 makefile --- makefile 1996/09/19 23:40:46 1.3 +++ makefile 2000/08/11 14:51:43 @@ -44,7 +44,6 @@ SRC += setsid.c SRC += setuid.c SRC += sleep.c -SRC += symlink.c SRC += sysconf.c SRC += ttyname.c SRC += unlink.s Index: djgpp/src/libc/posix/unistd/symlink.c =================================================================== RCS file: symlink.c diff -N symlink.c --- /tmp/cvs31493faa Fri Aug 11 10:53:47 2000 +++ /dev/null Tue May 5 16:32:27 1998 @@ -1,181 +0,0 @@ -/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ -/* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static char EXE_SUFFIX[] = ".exe"; -static char STUBIFY[] = "stubify.exe"; -static char STUBEDIT[] = "stubedit.exe"; - -/* Return a pointer to the tail of the pathname. */ -static const char * -tail (const char *path) -{ - const char *p = path && path[0] ? path + strlen (path) - 1 : path; - - if (p) - { - while (p > path && *p != '/' && *p != '\\' && *p != ':') - p--; - if (p > path) - p++; - } - return p; -} - -/* - This returns - -1, when the file does not exist - 0, when it is not a v2 executable - 1, when it is a v2 executable -*/ - -static int is_v2_prog(const char *program) -{ - const _v2_prog_type *type; - - type = _check_v2_prog (program, -1); - - if (!type->valid) - return -1; - - if (type->object_format != _V2_OBJECT_FORMAT_COFF) - return 0; - - if (type->version.v.major < 2) - return 0; - - return 1; -} - -/* Support the DJGPP ``symlinks'' for .exe files. */ -int -symlink (const char *source, const char *dest) -{ - char src_abs[FILENAME_MAX+5], src_short[FILENAME_MAX+5]; - char dest_abs[FILENAME_MAX+5]; - char *np, ropt[FILENAME_MAX+15]; /* some extra for ``runfile='' */ - const char *src_base, *dest_base; - - int v2_prog = 0; - - _fixpath (source, src_abs); - _fixpath (dest, dest_abs); - src_base = tail (src_abs); - dest_base = tail (dest_abs); - - /* DJGPP symlinks must be in the same directory. */ - if (src_base - src_abs != dest_base - dest_abs - || strnicmp (src_abs, dest_abs, src_base - src_abs)) - { - errno = EXDEV; - return -1; - } - - /* Any file is already a link to itself. */ - if (stricmp (src_abs, dest_abs) == 0) - return 0; - - /* Check at first, if the given name is a v2 executable (may be - unstubbed COFF image) */ - v2_prog = is_v2_prog(src_abs); - - /* It is an existing file but no v2 executable */ - if (v2_prog == 0) - { - errno = EXDEV; - return -1; - } - - /* Allow to say `ln -s src dest' when we really - mean `src.exe' and `dest.exe' */ - np = src_abs + strlen (src_abs); - if (np - src_abs > 4 && stricmp (np - 4, EXE_SUFFIX) != 0) - { - strcat (src_abs, EXE_SUFFIX); - /* Now test again for v2 executable, but only if not already - succeed. */ - v2_prog = v2_prog == 1 ? v2_prog : is_v2_prog(src_abs); - } - - /* It is an existing file but no v2 executable */ - if (v2_prog == 0) - { - errno = EXDEV; - return -1; - } - - /* When we are here, either the file exists and is a v2 executable - or it does not exist and we hope, the the user knows what he - does. */ - - /* Under LFN, we need the short version of the program name, since that - is what the stub stores (and what a program gets in its argv[0]). */ - if (_USE_LFN) - { - if (__file_exists (src_abs)) - { - /* File exists. Get its 8+3 alias. */ - __dpmi_regs r; - - dosmemput(src_abs, strlen (src_abs)+1, __tb); - r.x.ax = 0x7160; /* Truename */ - r.x.cx = 1; /* Get short name */ - r.x.ds = r.x.es = __tb / 16; - r.x.si = r.x.di = __tb & 15; - __dpmi_int(0x21, &r); - if (r.x.flags & 1 || r.x.ax == 0x7100) - /* Shouldn't happen: LFN *is* supported and file *does* exist. */ - { - errno = EIO; - return -1; - } - dosmemget (__tb, FILENAME_MAX, src_short); - } - else - { - /* File doesn't exist. Generate short name that would be used. - FIXME: this will lose if the generated name collides with - another file already in that directory; however, the only - alternative is to disallow symlinks to non-existing files. */ - char *p = strncpy (src_short, src_abs, src_base - src_abs); - _lfn_gen_short_fname (src_base, p + (src_base - src_abs)); - } - } - else - strcpy (src_short, src_abs); - - /* Need the basename of SRC_SHORT sans the extension. */ - strcpy (ropt, "runfile="); - strcat (ropt, tail (src_short)); - for (np = ropt + strlen (ropt) - 1; np > ropt; np--) - if (*np == '.') - { - *np = '\0'; - break; - } - - /* `stubedit' needs its argument with the .EXE suffix explicit. */ - np = dest_abs + strlen (dest_abs); - if (np - dest_abs > 4 && stricmp (np - 4, EXE_SUFFIX) != 0) - strcat (dest_abs, EXE_SUFFIX); - - /* Any file is already a link to itself. */ - if (stricmp (src_abs, dest_abs) == 0) - return 0; - - if (spawnlp (P_WAIT, STUBIFY, STUBIFY, "-g", dest_abs, (char *)0) - || spawnlp (P_WAIT, STUBEDIT, STUBEDIT, dest_abs, ropt, (char *)0)) - return -1; - return 0; -} Index: djgpp/src/libc/posix/unistd/symlink.txh =================================================================== RCS file: symlink.txh diff -N symlink.txh --- /tmp/cvs31493gaa Fri Aug 11 10:53:47 2000 +++ /dev/null Tue May 5 16:32:27 1998 @@ -1,48 +0,0 @@ -@node symlink, io -@subheading Syntax - -@example -#include - -int symlink(const char *exists, const char *new); -@end example - -@subheading Description -MSDOS doesn't support symbolic links. However, DJGPP supports -``symlinks'' to DJGPP programs. This function simulates a symlink -between two @file{.exe} files in the DJGPP style. It creates a program -whose name is pointed to by @var{new} which, when run, will actually -execute the program @var{exists} passing it the string pointed by -@var{new} in @code{argv[0]} (some programs change their behavior -depending on what's passed in @code{argv[0]}). The file referred to by -@var{exists} doesn't really have to exist when this function is called. -If @var{exists} points to an @emph{existing} file, the function checks -that it is a DJGPP executable; if not, the call will fail with -@code{EXDEV}. - -Both @var{new} and @var{exists} can point to a name with or without the -@file{.exe} extension. - -Note that both @var{exists} and @var{new} must specify file names which -reside in the same -directory (this is a restriction of the DJGPP ``symlinks''); the -function will fail and set @code{errno} to @code{EXDEV} if they aren't. - -This functions runs the @samp{stubify} and @samp{stubedit} programs, so -they should be somewhere on your @samp{PATH} for the function to -succeed. (These programs come with the DJGPP development distribution.) - -@subheading Return Value - -Zero in case of success, -1 in case of failure (and @code{errno} set to -the appropriate error code). - -@subheading Portability - -@portability !ansi, !posix - -@subheading Example - -@example -symlink ("c:/djgpp/bin/grep", "c:/djgpp/bin/fgrep"); -@end example Index: djgpp/tests/libc/compat/unistd/makefile =================================================================== RCS file: /cvs/djgpp/djgpp/tests/libc/compat/unistd/makefile,v retrieving revision 1.1 diff -u -r1.1 makefile --- makefile 2000/08/11 11:16:25 1.1 +++ makefile 2000/08/11 14:51:48 @@ -1,5 +1,7 @@ TOP=../.. SRC += readlink.c +SRC += symlink.c +SRC += xsymlink.c include $(TOP)/../makefile.inc Index: djgpp/tests/libc/compat/unistd/symlink.c =================================================================== RCS file: symlink.c diff -N symlink.c --- /dev/null Tue May 5 16:32:27 1998 +++ symlink.c Fri Aug 11 10:51:48 2000 @@ -0,0 +1,68 @@ +/* Testsuite for symlink() */ +#include +#include +#include + +#define LINK_CONT "whatever.file" + +static void test_failure(int test_no, const char * source, const char * target, + int expect_errno); + +int main(void) +{ + char *link_name; + char fn[FILENAME_MAX + 1]; + int bytes_read; + if (!__file_exists("fail1") || !__file_exists("fail2")) + { + fprintf(stderr, "Cannot run testsuite - required data files not found\n"); + exit(1); + } + printf("Running symlink() testsuite:\n"); + /* Test if symlink generated file is understandable by readlink() */ + link_name = tmpnam(NULL); + if (symlink(LINK_CONT, link_name)) + { + fprintf(stderr, "Test 1 failed - unexpected symlink failure\n"); + exit(1); + } + bytes_read = readlink(link_name, fn, FILENAME_MAX); + if (bytes_read == -1) + { + fprintf(stderr, "Test 1 failed - cannot read link made with symlink()\n"); + exit(1); + } + fn[bytes_read] = '\0'; + if (strcmp(LINK_CONT, fn)) + { + fprintf(stderr, "Test 1 failed - wrong link contents\n"); + exit(1); + } + printf("Test 1 passed\n"); + remove(link_name); + test_failure(2, NULL, "who.cares", EINVAL); + test_failure(3, "cares.who", NULL, EINVAL); + test_failure(4, "middle.of.nowhere", "fail1", ELOOP); + test_failure(5, "nowhere.in.middle", "/dev/env/DJDIR/djgpp.env", EEXIST); + return 0; +} + +static void test_failure(int test_no, const char * source, const char * target, + int expect_errno) +{ + errno = 0; + if (!symlink(source, target)) + { + fprintf(stderr, + "Test %d failed - unexpected symlink() success\n", test_no); + exit(1); + } + if (errno != expect_errno) + { + char buf[50]; + sprintf(buf, "Test %d failed - wrong errno value ", test_no); + perror(buf); + exit(1); + } + printf("Test %d passed\n", test_no); +}