Mail Archives: djgpp-workers/2005/01/12/23:54:17
On Thu, 23 Dec 2004 21:51:47 +0200, Eli Zaretskii <eliz AT gnu DOT org> wrote:
>> Date: Wed, 22 Dec 2004 22:42:41 -0700
>> From: Brian Inglis <Brian DOT Inglis AT SystematicSw DOT ab DOT ca>
>>
>> > if (spawnlp (P_WAIT, STUBIFY, STUBIFY, "-g", dest_abs, (char *)0)
>> > || spawnlp (P_WAIT, STUBEDIT, STUBEDIT, dest_abs, ropt, (char *)0))
>> > return -1;
>> >
>> >Should we create a v2.04 style symlink if stubify and/or stubedit
>> >failed in this fragment? I don't know.
>>
>> I guess some research into the failure modes and return codes of
>> stubify and stubedit are in order.
>
>Indeed.
>
>> The intermingling of 2.03 and 2.04 symlinks is looking more
>> interesting (as in the Chinese curse!)
>
>Happy hacking!
I've read everything useful I could find on the workers archives
about the old and new symlinks.
I'd like some review feedback on the design and implementation
of a version of symlink that creates new symlinks unless
a v2 prog exists or an exe file is specified and does not exist.
It started out as a version of old symlink that called the new
symlink instead of returning an error code, and the design and
implementation has evolved from there.
Any/all comments, suggestions, questions about the approach
taken or the appended code are welcome.
It's compilable and could be tested, but I'm not yet ready to
take that step, until I find out if the design decisions can
be considered valid.
Thanks. Take care, Brian Inglis
/* Copyright (C) 2005 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2004 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
/* 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/fsexthlp.h>
#include <libc/symlink.h>
#include <sys/fsext.h>
#include <sys/stat.h>
#include <sys/system.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dpmi.h>
#include <fcntl.h>
#include <go32.h>
#include <io.h>
#include <process.h>
#include <unistd.h>
#include "xsymlink.h"
/* Emulate symlinks for all files */
static int
softlink(const char *src, const char *dst)
{
int symlink_file;
static char fill_buf[_SYMLINK_FILE_LEN - _SYMLINK_PREFIX_LEN + 1] =
"\nThis 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 - _SYMLINK_PREFIX_LEN - strlen(fill_buf));
if ((symlink_file = _creat(dst, 0)) < 0)
return -1; /* Return errno from creat() call */
write(symlink_file, _SYMLINK_PREFIX, _SYMLINK_PREFIX_LEN);
write(symlink_file, src, strlen(src));
write(symlink_file, fill_buf,
_SYMLINK_FILE_LEN - _SYMLINK_PREFIX_LEN - strlen(src));
_close(symlink_file);
return 0;
}
/*
is_v2_prog returns:
non-zero, when program is a v2 executable
zero, when program is NOT a v2 executable
*/
static int
is_v2_prog(const char *program)
{
const _v2_prog_type *type = _check_v2_prog(program, -1);
return (type && type->valid && type->version.v.major >= 2
&& type->object_format == _V2_OBJECT_FORMAT_COFF);
}
/* get file's 8+3 alias */
static char *
get_shorty( char *short_name, const char *long_name, int short_len)
{
__dpmi_regs r;
dosmemput(long_name, strlen(long_name)+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. */
return NULL;
dosmemget(__tb, short_len, short_name);
return short_name;
}
static const char EXE_SUFFIX[] = ".exe";
static const char STUBIFY[] = "stubify.exe";
static const char STUBEDIT[] = "stubedit.exe";
/* Support the DJGPP ``symlinks'' for .exe files. */
int
symlink(const char *src, const char *dst)
{
char ropt[PATH_MAX+10] = "runfile=";
char src_real[PATH_MAX];
char src_abs[PATH_MAX];
char src_short[PATH_MAX];
char dst_real[PATH_MAX];
char dst_abs[PATH_MAX];
char * src_base;
char * dst_base;
char * np;
int ret;
/* Common error conditions */
if (!src || !dst || !*src || !*dst)
{
errno = EINVAL;
return -1;
}
/* Provide ability to hook symlink support */
if (__FSEXT_call_open_handlers_wrapper(__FSEXT_symlink, &ret, src, dst))
return ret;
/* src may have symlinks in the path */
if (!__solve_symlinks(src, src_real))
return -1; /* Errno (ELOOP) from __solve_symlinks() call. */
/* dst may have symlinks somewhere in the path */
if (!__solve_symlinks(dst, dst_real))
return -1; /* Errno (ELOOP) from __solve_symlinks() call. */
_fixpath(src_real, src_abs);
_fixpath(dst_real, dst_abs);
/* Any file is already a link to itself. */
if (stricmp(src_abs, dst_abs) == 0)
return 0;
/* Check if there already is file with symlink's name */
if (__file_exists(dst_abs))
{
errno = EEXIST;
return -1;
}
src_base = basename(src_abs);
dst_base = basename(dst_abs);
/* DJGPP symlinks must be in the same directory. */
if (src_base - src_abs != dst_base - dst_abs
|| strnicmp (src_abs, dst_abs, src_base - src_abs))
{
/* not in same directory */
return softlink( src, dst_real);
}
/* check if src exists */
if (__file_exists(src_abs))
{
/* Check at first, if the given name is a v2 executable (may be
unstubbed COFF image) */
if (!is_v2_prog(src_abs))
{
/* not v2 executable */
return softlink( src, dst_real);
}
}
else /* src does not exist */
{
/* if src base name has no suffix */
if (!(np = strrchr( src_base, '.')))
{
/* add exe suffix */
strcat(src_base, EXE_SUFFIX);
/* check if exe exists */
if (__file_exists(src_abs))
{
/* Now test again for v2 executable */
if (!is_v2_prog(src_abs))
{
/* not v2 executable */
return softlink( src, dst_real);
}
}
}
else /* src already has suffix */
{
/* if suffix wrong length or not exe */
if (np != src_base + strlen( src_base ) - strlen( EXE_SUFFIX )
|| stricmp( np, EXE_SUFFIX))
return softlink( src, dst_real);
} /* src already has suffix */
} /* src does not exist */
/* 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. */
if (!get_shorty( src_short, src_abs, PATH_MAX))
{
return softlink( src, dst_real);
}
}
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. */
strcat(ropt, basename(src_short));
if ((np = strrchr( ropt, '.')))
*np = '\0';
/* `stubedit' needs its argument with the .EXE suffix explicit. */
np = dst_abs + strlen(dst_abs);
if (np - strlen( EXE_SUFFIX ) > dst_abs
&& stricmp(np - strlen( EXE_SUFFIX ), EXE_SUFFIX))
strcpy(np, EXE_SUFFIX);
if (spawnlp(P_WAIT, STUBIFY, STUBIFY, "-g", dst_abs, NULL)
|| spawnlp(P_WAIT, STUBEDIT, STUBEDIT, dst_abs, ropt, NULL))
return -1;
return 0;
}
- Raw text -