www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2000/08/11/10:58:17

Message-ID: <39941478.329CA50B@softhome.net>
Date: Fri, 11 Aug 2000 16:58:00 +0200
From: Laurynas Biveinis <lauras AT softhome DOT net>
X-Mailer: Mozilla 4.74 [en] (Win98; U)
X-Accept-Language: lt,en
MIME-Version: 1.0
To: DJGPP Workers <djgpp-workers AT delorie DOT com>
Subject: Patch: symlink()
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 <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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019