/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ #include #include #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[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; }