Mail Archives: djgpp-workers/1997/05/20/05:57:18
During my port of binutils 2.8 I found an annoing thing with
ln.exe.
When running on W95 with long filenames enabled, the following
command will success!!
ln -s foo.c foo_s.c
and produces a file foo_s.c.exe
When running under no LFN this will produce an error and
nonzero exit code of ln.exe (which is OK).
To fix this I wrote a little patch for symlink.c. Please
read the comments inside the patch, because the current
behaviour of ln is in my opinion not correct.
ln -s foo dummy
is OK even when foo or foo.exe not exists. This may be
a feature or not. I think it is a misfeature but I have
not changed this beahaviour (I commented it only and
wrote how to disable this).
I have also updated the doc to reflect my changes.
*** src/libc/posix/unistd/symlink.c~ Thu Sep 19 22:40:46 1996
--- src/libc/posix/unistd/symlink.c Wed May 14 21:36:52 1997
***************
*** 29,34 ****
--- 29,106 ----
return p;
}
+ /*
+ This code is borrowed from dosexec.c
+ It 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)
+ {
+ int is_stubbed = 0, is_coff = 0;
+ unsigned short header[3];
+ int pf;
+ int stub_offset;
+
+ int v2_0 = 0;
+
+ pf = open(program, O_RDONLY|O_BINARY);
+
+ if (pf < 0)
+ return -1;
+
+ read(pf, header, sizeof(header));
+ if (header[0] == 0x010b || header[0] == 0x014c)
+ {
+ unsigned char firstbytes[1];
+ unsigned long coffhdr[40];
+
+ /* Seems to be an unstubbed COFF. See what the first opcode
+ is to determine if it's v1.x or v2 COFF (or an impostor).
+
+ FIXME: the code here assumes that any COFF that's not a V1
+ can only be V2. What about other compilers that use COFF? */
+ is_coff = 1;
+ if (lseek(pf, 2, 1) < 0
+ || read(pf, coffhdr, sizeof(coffhdr)) != sizeof(coffhdr)
+ || lseek(pf, coffhdr[10 + 5], 0) < 0
+ || read(pf, firstbytes, 1) != 1) /* scnptr */
+ is_coff = 0; /* "Aha! An impostor!" (The Adventure game) */
+ else if (firstbytes[0] != 0xa3) /* opcode of movl %eax, 0x12345678 (V1) */
+ v2_0 = 1;
+ }
+ else if (header[0] == 0x5a4d) /* "MZ" */
+ {
+ int header_offset = (long)header[2]*512L;
+ char cmdline[9];
+ is_stubbed = 1;
+ if (header[1])
+ header_offset += (long)header[1] - 512L;
+ lseek(pf, 512, 0);
+ read(pf, cmdline, 8);
+ cmdline[8] = 0;
+ if (strcmp(cmdline, "go32stub") == 0)
+ {
+ v2_0 = 1;
+ is_coff = 1;
+ }
+ else
+ {
+ lseek(pf, header_offset - 4, 0);
+ read(pf, &stub_offset, 4);
+ header[0] = 0;
+ read(pf, header, sizeof(header));
+ if (header[0] == 0x010b)
+ is_coff = 1;
+ if (header[0] == 0x014c)
+ is_coff = 1;
+ }
+ }
+ close(pf);
+ return is_coff && v2_0;
+ }
+
/* Support the DJGPP ``symlinks'' for .exe files. */
int
symlink (const char *source, const char *dest)
***************
*** 38,43 ****
--- 110,117 ----
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);
***************
*** 54,64 ****
--- 128,172 ----
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) - 4;
if (stricmp (np, EXE_SUFFIX))
+ {
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);
+ }
+
+ /* Comment by RH:
+ In my opinion here should be
+ if (v2_prog != 1)
+ which means, to allow a symlink ONLY to real existing
+ v2 executable. But I don't want to change too much at the
+ current behaviour of this function.
+ */
+ /* 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]). */
*** src/libc/posix/unistd/symlink.tx~ Thu Sep 19 22:41:08 1996
--- src/libc/posix/unistd/symlink.txh Wed May 14 21:41:54 1997
***************
*** 23,29 ****
directory (this is a restriction of the DJGPP ``symlinks''); the
function will fail and set @code{errno} to @code{EXDEV} if they aren't.
Also note that this function does nothing to ensure that @var{*exists}
! is actually a DJGPP program.
This functions runs the @samp{stubify} and @samp{stubedit} programs, so
they should be somewhere on your @samp{PATH} for the function to
--- 23,31 ----
directory (this is a restriction of the DJGPP ``symlinks''); the
function will fail and set @code{errno} to @code{EXDEV} if they aren't.
Also note that this function does nothing to ensure that @var{*exists}
! is actually a DJGPP program whith the exception, that if the file
! @var{*exists} does really exist and it is not a usable DJGPP executable,
! this function will also fail with @code{errno} set to @code{EXDEV}.
This functions runs the @samp{stubify} and @samp{stubedit} programs, so
they should be somewhere on your @samp{PATH} for the function to
- Raw text -