* cygcheck.cc (get_word, get_dword): Move to path.cc.

(LINK_EXTENSION): New macro.
	(check_existence): New static function.
	(find_on_path): Check for symbolic links if asked.
	(dll_info): New error handling.
	(track_down): Only call dll_info() for executables, display
	an error for symlinks, and print magic number for others.
	(find_app_on_path): New static function.
	(cygcheck, dump_sysinfo): Call find_app_on_path() instead of
	find_on_path().
	* path.cc (cmp_shortcut_header): New static function.
	(get_word, get_dword): Moved from cygcheck.cc.
	(EXE_MAGIC, SHORTCUT_MAGIC, SYMLINK_COOKIE, SYMLINK_MAGIC): New
	macros.
	(is_exe, is_symlink, readlink): New functions.
	* path.h (is_exe, is_symlink, readlink): Declare.
	(get_word, get_dword): Ditto.
This commit is contained in:
Corinna Vinschen 2006-10-05 17:24:13 +00:00
parent 66845c62b1
commit cea9b62102
4 changed files with 363 additions and 46 deletions

View File

@ -1,3 +1,23 @@
2006-10-05 Igor Peshansky <pechtcha@cs.nyu.edu>
* cygcheck.cc (get_word, get_dword): Move to path.cc.
(LINK_EXTENSION): New macro.
(check_existence): New static function.
(find_on_path): Check for symbolic links if asked.
(dll_info): New error handling.
(track_down): Only call dll_info() for executables, display
an error for symlinks, and print magic number for others.
(find_app_on_path): New static function.
(cygcheck, dump_sysinfo): Call find_app_on_path() instead of
find_on_path().
* path.cc (cmp_shortcut_header): New static function.
(get_word, get_dword): Moved from cygcheck.cc.
(EXE_MAGIC, SHORTCUT_MAGIC, SYMLINK_COOKIE, SYMLINK_MAGIC): New
macros.
(is_exe, is_symlink, readlink): New functions.
* path.h (is_exe, is_symlink, readlink): Declare.
(get_word, get_dword): Ditto.
2006-09-12 Christopher Faylor <cgf@timesys.com>
* Makefile.in: Fix -ntdll typo.

View File

@ -249,9 +249,41 @@ init_paths ()
}
}
#define LINK_EXTENSION ".lnk"
static bool
check_existence (char *file, int showall, int foundone, char *first)
{
if (GetFileAttributes (file) != (DWORD) - 1)
{
char *lastdot = strrchr (file, '.');
bool is_link = lastdot && !strcmp (lastdot, LINK_EXTENSION);
// If file is a link, fix up the extension before printing
if (is_link)
*lastdot = '\0';
if (showall)
printf ("Found: %s\n", file);
if (foundone)
{
char *flastdot = strrchr (first, '.');
bool f_is_link = flastdot && !strcmp (flastdot, LINK_EXTENSION);
// if first is a link, fix up the extension before printing
if (f_is_link)
*flastdot = '\0';
printf ("Warning: %s hides %s\n", first, file);
if (f_is_link)
*flastdot = '.';
}
if (is_link)
*lastdot = '.';
return true;
}
return false;
}
static char *
find_on_path (char *file, char *default_extension,
int showall = 0, int search_sysdirs = 0)
int showall = 0, int search_sysdirs = 0, int checklinks = 0)
{
static char rv[4000];
char tmp[4000], *ptr = rv;
@ -270,11 +302,21 @@ find_on_path (char *file, char *default_extension,
if (strchr (file, ':') || strchr (file, '\\') || strchr (file, '/'))
{
// FIXME: this will find "foo" before "foo.exe" -- contrary to Windows
char *fn = cygpath (file, NULL);
if (access (fn, F_OK) == 0)
return fn;
strcpy (rv, fn);
strcat (rv, default_extension);
if (access (rv, F_OK) == 0)
return rv;
if (!checklinks)
return fn;
strcat (rv, LINK_EXTENSION);
if (access (rv, F_OK) == 0)
return rv;
strcpy (rv, fn);
strcat (rv, LINK_EXTENSION);
return access (rv, F_OK) == 0 ? strdup (rv) : fn;
}
@ -286,14 +328,25 @@ find_on_path (char *file, char *default_extension,
if (i == 0 || !search_sysdirs || strcasecmp (paths[i], paths[0]))
{
sprintf (ptr, "%s\\%s%s", paths[i], file, default_extension);
if (GetFileAttributes (ptr) != (DWORD) - 1)
{
if (showall)
printf ("Found: %s\n", ptr);
if (ptr == tmp && verbose)
printf ("Warning: %s hides %s\n", rv, ptr);
ptr = tmp;
}
if (check_existence (ptr, showall, ptr == tmp && verbose, rv))
ptr = tmp;
if (!checklinks)
continue;
sprintf (ptr, "%s\\%s%s%s", paths[i], file, default_extension, LINK_EXTENSION);
if (check_existence (ptr, showall, ptr == tmp && verbose, rv))
ptr = tmp;
if (!*default_extension)
continue;
sprintf (ptr, "%s\\%s", paths[i], file);
if (check_existence (ptr, showall, ptr == tmp && verbose, rv))
ptr = tmp;
sprintf (ptr, "%s\\%s%s", paths[i], file, LINK_EXTENSION);
if (check_existence (ptr, showall, ptr == tmp && verbose, rv))
ptr = tmp;
}
}
@ -330,38 +383,6 @@ already_did (char *file)
return d;
}
static int
get_word (HANDLE fh, int offset)
{
short rv;
unsigned r;
if (SetFilePointer (fh, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER
&& GetLastError () != NO_ERROR)
display_error ("get_word: SetFilePointer()");
if (!ReadFile (fh, &rv, 2, (DWORD *) &r, 0))
display_error ("get_word: Readfile()");
return rv;
}
static int
get_dword (HANDLE fh, int offset)
{
int rv;
unsigned r;
if (SetFilePointer (fh, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER
&& GetLastError () != NO_ERROR)
display_error ("get_dword: SetFilePointer()");
if (!ReadFile (fh, &rv, 4, (DWORD *) &r, 0))
display_error ("get_dword: Readfile()");
return rv;
}
struct Section
{
char name[8];
@ -505,6 +526,8 @@ dll_info (const char *path, HANDLE fh, int lvl, int recurse)
DWORD junk;
int i;
int pe_header_offset = get_dword (fh, 0x3c);
if (GetLastError () != NO_ERROR)
display_error ("get_dword");
int opthdr_ofs = pe_header_offset + 4 + 20;
unsigned short v[6];
@ -528,12 +551,24 @@ dll_info (const char *path, HANDLE fh, int lvl, int recurse)
printf ("\n");
int num_entries = get_dword (fh, opthdr_ofs + 92);
if (GetLastError () != NO_ERROR)
display_error ("get_dword");
int export_rva = get_dword (fh, opthdr_ofs + 96);
if (GetLastError () != NO_ERROR)
display_error ("get_dword");
int export_size = get_dword (fh, opthdr_ofs + 100);
if (GetLastError () != NO_ERROR)
display_error ("get_dword");
int import_rva = get_dword (fh, opthdr_ofs + 104);
if (GetLastError () != NO_ERROR)
display_error ("get_dword");
int import_size = get_dword (fh, opthdr_ofs + 108);
if (GetLastError () != NO_ERROR)
display_error ("get_dword");
int nsections = get_word (fh, pe_header_offset + 4 + 2);
if (nsections == -1)
display_error ("get_word");
char *sections = (char *) malloc (nsections * 40);
if (SetFilePointer (fh, pe_header_offset + 4 + 20 +
@ -682,7 +717,20 @@ track_down (char *file, char *suffix, int lvl)
d->state = DID_ACTIVE;
dll_info (path, fh, lvl, 1);
if (is_exe (fh))
dll_info (path, fh, lvl, 1);
else if (is_symlink (fh))
printf (" - Found a symlink instead of a DLL\n");
else
{
int magic = get_word (fh, 0x0);
if (magic == -1)
display_error ("get_word");
magic &= 0x00FFFFFF;
printf (" - Not a DLL: magic number %x (%d) '%s'\n",
magic, magic, (char *)&magic);
}
d->state = DID_INACTIVE;
if (!CloseHandle (fh))
display_error ("track_down: CloseHandle()");
@ -711,11 +759,56 @@ ls (char *f)
display_error ("ls: CloseHandle()");
}
// Find a real application on the path (possibly following symlinks)
static char *
find_app_on_path (char *app, int showall = 0)
{
char *papp = find_on_path (app, (char *) ".exe", showall, 0, 1);
HANDLE fh =
CreateFile (papp, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fh == INVALID_HANDLE_VALUE)
{
printf (" - Cannot open\n");
return NULL;
}
if (is_symlink (fh))
{
static char tmp[4000] = "";
char *ptr;
if (!readlink (fh, tmp, 3999))
display_error("readlink failed");
ptr = cygpath (tmp, NULL);
for (char *p = ptr; (p = strchr (p, '/')); p++)
*p = '\\';
printf (" -> %s\n", ptr);
if (!strchr (ptr, '\\'))
{
char *lastsep;
strncpy (tmp, cygpath (papp, NULL), 3999);
for (char *p = tmp; (p = strchr (p, '/')); p++)
*p = '\\';
lastsep = strrchr (tmp, '\\');
strncpy (lastsep+1, ptr, 3999-(lastsep-tmp));
ptr = tmp;
}
if (!CloseHandle (fh))
display_error ("find_app_on_path: CloseHandle()");
return find_app_on_path (ptr, showall);
}
if (!CloseHandle (fh))
display_error ("find_app_on_path: CloseHandle()");
return papp;
}
// Return true on success, false if error printed
static bool
cygcheck (char *app)
{
char *papp = find_on_path (app, (char *) ".exe", 1, 0);
char *papp = find_app_on_path (app, 1);
if (!papp)
{
printf ("Error: could not find %s\n", app);
@ -1441,7 +1534,7 @@ dump_sysinfo ()
printf
("Looking to see where common programs can be found, if at all...\n");
for (i = 0; common_apps[i].name; i++)
if (!find_on_path ((char *) common_apps[i].name, (char *) ".exe", 1, 0))
if (!find_app_on_path ((char *) common_apps[i].name, 1))
{
if (common_apps[i].missing_is_good)
printf ("Not Found: %s (good!)\n", common_apps[i].name);

View File

@ -9,14 +9,16 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
/* The purpose of this file is to hide all the details about accessing
Cygwin's mount table. If the format or location of the mount table
changes, this is the file to change to match it. */
Cygwin's mount table, shortcuts, etc. If the format or location of
the mount table, or the shortcut format changes, this is the file to
change to match it. */
#define str(a) #a
#define scat(a,b) str(a##b)
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "path.h"
#include "cygwin/include/cygwin/version.h"
#include "cygwin/include/sys/mount.h"
#include "cygwin/include/mntent.h"
@ -29,6 +31,202 @@ details. */
})
static const GUID GUID_shortcut
= { 0x00021401L, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46 };
enum {
WSH_FLAG_IDLIST = 0x01, /* Contains an ITEMIDLIST. */
WSH_FLAG_FILE = 0x02, /* Contains a file locator element. */
WSH_FLAG_DESC = 0x04, /* Contains a description. */
WSH_FLAG_RELPATH = 0x08, /* Contains a relative path. */
WSH_FLAG_WD = 0x10, /* Contains a working dir. */
WSH_FLAG_CMDLINE = 0x20, /* Contains command line args. */
WSH_FLAG_ICON = 0x40 /* Contains a custom icon. */
};
struct win_shortcut_hdr
{
DWORD size; /* Header size in bytes. Must contain 0x4c. */
GUID magic; /* GUID of shortcut files. */
DWORD flags; /* Content flags. See above. */
/* The next fields from attr to icon_no are always set to 0 in Cygwin
and U/Win shortcuts. */
DWORD attr; /* Target file attributes. */
FILETIME ctime; /* These filetime items are never touched by the */
FILETIME mtime; /* system, apparently. Values don't matter. */
FILETIME atime;
DWORD filesize; /* Target filesize. */
DWORD icon_no; /* Icon number. */
DWORD run; /* Values defined in winuser.h. Use SW_NORMAL. */
DWORD hotkey; /* Hotkey value. Set to 0. */
DWORD dummy[2]; /* Future extension probably. Always 0. */
};
static bool
cmp_shortcut_header (win_shortcut_hdr *file_header)
{
/* A Cygwin or U/Win shortcut only contains a description and a relpath.
Cygwin shortcuts also might contain an ITEMIDLIST. The run type is
always set to SW_NORMAL. */
return file_header->size == sizeof (win_shortcut_hdr)
&& !memcmp (&file_header->magic, &GUID_shortcut, sizeof GUID_shortcut)
&& (file_header->flags & ~WSH_FLAG_IDLIST)
== (WSH_FLAG_DESC | WSH_FLAG_RELPATH)
&& file_header->run == SW_NORMAL;
}
int
get_word (HANDLE fh, int offset)
{
unsigned short rv;
unsigned r;
SetLastError(NO_ERROR);
if (SetFilePointer (fh, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER
&& GetLastError () != NO_ERROR)
return -1;
if (!ReadFile (fh, &rv, 2, (DWORD *) &r, 0))
return -1;
return rv;
}
/*
* Check the value of GetLastError() to find out whether there was an error.
*/
int
get_dword (HANDLE fh, int offset)
{
int rv;
unsigned r;
SetLastError(NO_ERROR);
if (SetFilePointer (fh, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER
&& GetLastError () != NO_ERROR)
return -1;
if (!ReadFile (fh, &rv, 4, (DWORD *) &r, 0))
return -1;
return rv;
}
#define EXE_MAGIC ((int)*(unsigned short *)"MZ")
#define SHORTCUT_MAGIC ((int)*(unsigned short *)"L\0")
#define SYMLINK_COOKIE "!<symlink>"
#define SYMLINK_MAGIC ((int)*(unsigned short *)SYMLINK_COOKIE)
bool
is_exe (HANDLE fh)
{
int magic = get_word (fh, 0x0);
return magic == EXE_MAGIC;
}
bool
is_symlink (HANDLE fh)
{
int magic = get_word (fh, 0x0);
if (magic != SHORTCUT_MAGIC && magic != SYMLINK_MAGIC)
return false;
DWORD got;
BY_HANDLE_FILE_INFORMATION local;
if (!GetFileInformationByHandle (fh, &local))
return false;
if (magic == SHORTCUT_MAGIC)
{
DWORD size;
if (!local.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
return false; /* Not a Cygwin symlink. */
if ((size = GetFileSize (fh, NULL)) > 8192)
return false; /* Not a Cygwin symlink. */
char buf[size];
SetFilePointer (fh, 0, 0, FILE_BEGIN);
if (!ReadFile (fh, buf, size, &got, 0))
return false;
if (got != size || !cmp_shortcut_header ((win_shortcut_hdr *) buf))
return false; /* Not a Cygwin symlink. */
/* TODO: check for invalid path contents
(see symlink_info::check() in ../cygwin/path.cc) */
}
else /* magic == SYMLINK_MAGIC */
{
if (!local.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
return false; /* Not a Cygwin symlink. */
char buf[sizeof (SYMLINK_COOKIE) - 1];
SetFilePointer (fh, 0, 0, FILE_BEGIN);
if (!ReadFile (fh, buf, sizeof (buf), &got, 0))
return false;
if (got != sizeof (buf) ||
memcmp (buf, SYMLINK_COOKIE, sizeof (buf)) != 0)
return false; /* Not a Cygwin symlink. */
}
return true;
}
/* Assumes is_symlink(fh) is true */
bool
readlink (HANDLE fh, char *path, int maxlen)
{
int got;
int magic = get_word (fh, 0x0);
if (magic == SHORTCUT_MAGIC)
{
int offset = get_word (fh, 0x4c);
int slen = get_word (fh, 0x4c + offset + 2);
if (slen >= maxlen)
{
SetLastError (ERROR_FILENAME_EXCED_RANGE);
return false;
}
if (SetFilePointer (fh, 0x4c + offset + 4, 0, FILE_BEGIN) ==
INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
return false;
if (!ReadFile (fh, path, slen, (DWORD *) &got, 0))
return false;
else if (got < slen)
{
SetLastError (ERROR_READ_FAULT);
return false;
}
else
path[got] = '\0';
}
else if (magic == SYMLINK_MAGIC)
{
char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
if (SetFilePointer (fh, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER
&& GetLastError () != NO_ERROR)
return false;
if (!ReadFile (fh, cookie_buf, sizeof (cookie_buf), (DWORD *) &got, 0))
return false;
else if (got == sizeof (cookie_buf)
&& memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
{
if (!ReadFile (fh, path, maxlen, (DWORD *) &got, 0))
return false;
else if (got >= maxlen)
{
SetLastError (ERROR_FILENAME_EXCED_RANGE);
path[0] = '\0';
return false;
}
else
path[got] = '\0';
}
}
else
return false;
return true;
}
static struct mnt
{
const char *native;

View File

@ -9,3 +9,9 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
char *cygpath (const char *s, ...);
bool is_exe (HANDLE);
bool is_symlink (HANDLE);
bool readlink (HANDLE, char *, int);
int get_word (HANDLE, int);
int get_dword (HANDLE, int);