Date: Wed, 18 Sep 1996 18:54:57 +0200 (IST) From: Eli Zaretskii To: djgpp-workers AT delorie DOT com Subject: `symlink' Message-Id: Mime-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII I wrote this for the port of GNU `ln' (so you could say something like "ln -s grep fgrep" and get fgrep.exe that runs grep.exe), so I though it might as well be in the library. *** src/libc/posix/unistd/symlink.c~0 Tue Sep 17 19:13:26 1996 --- src/libc/posix/unistd/symlink.c Wed Sep 18 08:22:54 1996 *************** *** 0 **** --- 1,119 ---- + #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 + strlen (path) - 1 : path; + + if (p) + { + while (p > path && *p != '/' && *p != '\\' && *p != ':') + p--; + if (p > path) + p++; + } + return p; + } + + /* 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; + + _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 (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; + + /* 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); + + /* 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) - 4; + if (stricmp (np, EXE_SUFFIX)) + strcat (dest_abs, EXE_SUFFIX); + + + 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; + } *** src/libc/posix/unistd/symlink.t~0 Wed Sep 18 09:12:16 1996 --- src/libc/posix/unistd/symlink.txh Wed Sep 18 09:16:02 1996 *************** *** 0 **** --- 1,41 ---- + @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 given by @var{*new} which, when run, will actually execute + the program @var{*exists} passing it @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. 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 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. + Also note that this function does nothing to ensure that @var{*exists} + is actually a DJGPP program. + + This functions runs the @samp{stabify} 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 Example + + @example + symlink ("c:/djgpp/bin/grep", "c:/djgpp/bin/fgrep"); + @end example *** src/libc/posix/unistd/makefile.~0~ Sat Jul 15 14:34:24 1995 --- src/libc/posix/unistd/makefile Wed Sep 18 17:34:08 1996 *************** *** 43,48 **** --- 43,49 ---- SRC += setsid.c SRC += setuid.c SRC += sleep.c + SRC += symlink.c SRC += sysconf.c SRC += ttyname.c SRC += unlink.s *** include/unistd.h~0 Sun Jun 18 05:48:26 1995 --- include/unistd.h Wed Sep 18 08:55:36 1996 *************** *** 129,134 **** --- 129,135 ---- char * getwd(char *__buffer); int nice(int _increment); void * sbrk(int _delta); + int symlink (const char *, const char *); int sync(void); int truncate(const char*, off_t); unsigned int usleep(unsigned int _useconds);