Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2006-10-05 21:24:13 +0400
committerCorinna Vinschen <corinna@vinschen.de>2006-10-05 21:24:13 +0400
commitcea9b62102c60a001f12b1709868716e3ee23cf5 (patch)
tree564aced29bbdf7aa03529e9a9cfe17057ba6a1ac /winsup/utils/path.cc
parent66845c62b18a89e2dd2f336a29cee9073e4fe3cd (diff)
* 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.
Diffstat (limited to 'winsup/utils/path.cc')
-rw-r--r--winsup/utils/path.cc202
1 files changed, 200 insertions, 2 deletions
diff --git a/winsup/utils/path.cc b/winsup/utils/path.cc
index 57bd3a4ff..356a60f01 100644
--- a/winsup/utils/path.cc
+++ b/winsup/utils/path.cc
@@ -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;