Mail Archives: djgpp-workers/2000/08/11/10:58:17
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 <libc/stubs.h>
+#include <libc/symlink.h>
+#include <errno.h>
+#include <unistd.h>
+#include <io.h>
+#include <stdio.h>
+
+#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 <unistd.h>
+
+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 <libc/stubs.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/system.h>
-#include <sys/stat.h>
-#include <process.h>
-#include <dpmi.h>
-#include <go32.h>
-
-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 <unistd.h>
-
-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 <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#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);
+}
- Raw text -