aboutsummaryrefslogtreecommitdiff
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2005-01-18 13:00:18 +0000
committerCorinna Vinschen <corinna@vinschen.de>2005-01-18 13:00:18 +0000
commitc20ec37fbd11cf18cf9201e218ceb022399883eb (patch)
tree4715de272fee2b9bd62f5de4f8e79ef8be5e6c58 /winsup
parent4d6b4804e9da71f901a7a1155f0287b8c02f8df3 (diff)
downloadnewlib-c20ec37fbd11cf18cf9201e218ceb022399883eb.zip
newlib-c20ec37fbd11cf18cf9201e218ceb022399883eb.tar.gz
newlib-c20ec37fbd11cf18cf9201e218ceb022399883eb.tar.bz2
* autoload.cc (CoInitialize): Remove.
(CoUninitialize): Remove. (CoCreateInstance): Remove. (CoTaskMemFree): Add. (SHGetDesktopFolder): Add. * path.cc (shortcut_header): Remove. (shortcut_initalized): Remove. (GUID_shortcut): New static GUID. (struct win_shortcut_hdr): New struct describing Windows shortcut header structure. (symlink_worker): Rewrite creating Windows shortcuts. Create ITEMIDLIST if target exists. Only write once. (cmp_shortcut_header): Use win_shortcut_hdr structure for comparison. (check_shortcut): Rewrite to read only once from file. Allow skipping an ITIMIDLIST in the file.
Diffstat (limited to 'winsup')
-rw-r--r--winsup/cygwin/ChangeLog18
-rw-r--r--winsup/cygwin/autoload.cc6
-rw-r--r--winsup/cygwin/path.cc214
3 files changed, 163 insertions, 75 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index ae1a2f7..bf93bf7 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,21 @@
+2005-01-18 Corinna Vinschen <corinna@vinschen.de>
+
+ * autoload.cc (CoInitialize): Remove.
+ (CoUninitialize): Remove.
+ (CoCreateInstance): Remove.
+ (CoTaskMemFree): Add.
+ (SHGetDesktopFolder): Add.
+ * path.cc (shortcut_header): Remove.
+ (shortcut_initalized): Remove.
+ (GUID_shortcut): New static GUID.
+ (struct win_shortcut_hdr): New struct describing Windows shortcut
+ header structure.
+ (symlink_worker): Rewrite creating Windows shortcuts. Create
+ ITEMIDLIST if target exists. Only write once.
+ (cmp_shortcut_header): Use win_shortcut_hdr structure for comparison.
+ (check_shortcut): Rewrite to read only once from file. Allow skipping
+ an ITIMIDLIST in the file.
+
2005-01-16 Christopher Faylor <cgf@timesys.com>
* pinfo.h (maybe_set_exit_code_from_windows): Renamed from
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index a50fcb2..5c2832a 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -492,9 +492,7 @@ LoadDLLfuncEx (GetIfEntry, 4, iphlpapi, 1)
LoadDLLfuncEx (GetIpAddrTable, 12, iphlpapi, 1)
LoadDLLfuncEx (GetNetworkParams, 8, iphlpapi, 1)
-LoadDLLfunc (CoInitialize, 4, ole32)
-LoadDLLfunc (CoUninitialize, 0, ole32)
-LoadDLLfunc (CoCreateInstance, 20, ole32)
+LoadDLLfunc (CoTaskMemFree, 4, ole32)
LoadDLLfuncEx (CancelIo, 4, kernel32, 1)
LoadDLLfuncEx (CreateHardLinkA, 12, kernel32, 1)
@@ -513,6 +511,8 @@ LoadDLLfuncEx (RegisterServiceProcess, 8, kernel32, 1)
LoadDLLfuncEx (SignalObjectAndWait, 16, kernel32, 1)
LoadDLLfuncEx (SwitchToThread, 0, kernel32, 1)
+LoadDLLfunc (SHGetDesktopFolder, 4, shell32)
+
LoadDLLfuncEx (waveOutGetNumDevs, 0, winmm, 1)
LoadDLLfuncEx (waveOutOpen, 24, winmm, 1)
LoadDLLfuncEx (waveOutReset, 4, winmm, 1)
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 0bfcb27..f49290a 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -59,6 +59,7 @@ details. */
#include <winuser.h>
#include <winnls.h>
#include <winnetwk.h>
+#include <shlobj.h>
#include <sys/cygwin.h>
#include <cygwin/version.h>
#include "cygerrno.h"
@@ -100,25 +101,38 @@ struct symlink_info
int pcheck_case = PCHECK_RELAXED; /* Determines the case check behaviour. */
-static char shortcut_header[SHORTCUT_HDR_SIZE];
-static bool shortcut_initalized;
+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. */
+};
-static void
-create_shortcut_header (void)
-{
- if (!shortcut_initalized)
- {
- shortcut_header[0] = 'L';
- shortcut_header[4] = '\001';
- shortcut_header[5] = '\024';
- shortcut_header[6] = '\002';
- shortcut_header[12] = '\300';
- shortcut_header[19] = 'F';
- shortcut_header[20] = '\f';
- shortcut_header[60] = '\001';
- shortcut_initalized = true;
- }
-}
+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. */
+ };
/* Determine if path prefix matches current cygdrive */
#define iscygdrive(path) \
@@ -2490,11 +2504,12 @@ symlink_worker (const char *topath, const char *frompath, bool use_winsym,
char from[CYG_MAX_PATH + 5];
char cwd[CYG_MAX_PATH + 1], *cp = NULL, c = 0;
char w32topath[CYG_MAX_PATH + 1];
+ char reltopath[CYG_MAX_PATH + 1] = { 0 };
DWORD written;
SECURITY_ATTRIBUTES sa = sec_none_nih;
security_descriptor sd;
- /* POSIX says that empty 'frompath' is invalid input whlie empty
+ /* POSIX says that empty 'frompath' is invalid input while empty
'topath' is valid -- it's symlink resolver job to verify if
symlink contents point to existing filesystem object */
if (check_null_empty_str_errno (topath) == EFAULT ||
@@ -2549,18 +2564,34 @@ symlink_worker (const char *topath, const char *frompath, bool use_winsym,
*cp = '\0';
chdir (from);
}
- backslashify (topath, w32topath, 0);
- }
- if (!cp || GetFileAttributes (w32topath) == INVALID_FILE_ATTRIBUTES)
- {
- win32_topath.check (topath, PC_SYM_NOFOLLOW);
- if (!cp || win32_topath.error != ENOENT)
- strcpy (w32topath, win32_topath);
+ backslashify (topath, reltopath, 0);
+ /* Creating an ITEMIDLIST requires an absolute path. So if we
+ create a shortcut file, we create relative and absolute Win32
+ paths, the first for the relpath field and the latter for the
+ ITEMIDLIST field. */
+ if (GetFileAttributes (reltopath) == INVALID_FILE_ATTRIBUTES)
+ {
+ win32_topath.check (topath, PC_SYM_NOFOLLOW);
+ if (win32_topath.error != ENOENT)
+ strcpy (use_winsym ? reltopath : w32topath, win32_topath);
+ }
+ else if (!use_winsym)
+ strcpy (w32topath, reltopath);
+ if (use_winsym)
+ {
+ win32_topath.check (topath, PC_FULL | PC_SYM_NOFOLLOW);
+ strcpy (w32topath, win32_topath);
+ }
+ if (cp)
+ {
+ *cp = c;
+ chdir (cwd);
+ }
}
- if (cp)
- {
- *cp = c;
- chdir (cwd);
+ else
+ {
+ win32_topath.check (topath, PC_FULL | PC_SYM_NOFOLLOW);
+ strcpy (w32topath, win32_topath);
}
create_how = CREATE_NEW;
}
@@ -2575,26 +2606,66 @@ symlink_worker (const char *topath, const char *frompath, bool use_winsym,
__seterrno ();
else
{
- BOOL success;
+ bool success = false;
if (use_winsym)
{
- create_shortcut_header ();
- /* Don't change the datatypes of `len' and `win_len' since
- their sizeof is used when writing. */
- unsigned short len = strlen (topath);
- unsigned short win_len = strlen (w32topath);
- success = WriteFile (h, shortcut_header, SHORTCUT_HDR_SIZE,
- &written, NULL)
- && written == SHORTCUT_HDR_SIZE
- && WriteFile (h, &len, sizeof len, &written, NULL)
- && written == sizeof len
- && WriteFile (h, topath, len, &written, NULL)
- && written == len
- && WriteFile (h, &win_len, sizeof win_len, &written, NULL)
- && written == sizeof win_len
- && WriteFile (h, w32topath, win_len, &written, NULL)
- && written == win_len;
+ /* A path of 240 chars with 120 one character directories in it
+ can result in a 6K shortcut. */
+ char *buf = (char *) alloca (8192);
+ win_shortcut_hdr *shortcut_header = (win_shortcut_hdr *) buf;
+ HRESULT hres;
+ IShellFolder *psl;
+ WCHAR wc_path[CYG_MAX_PATH + 1];
+ ITEMIDLIST *pidl = NULL, *p;
+ unsigned short len;
+
+ memset (shortcut_header, 0, sizeof *shortcut_header);
+ shortcut_header->size = sizeof *shortcut_header;
+ shortcut_header->magic = GUID_shortcut;
+ shortcut_header->flags = (WSH_FLAG_DESC | WSH_FLAG_RELPATH);
+ shortcut_header->run = SW_NORMAL;
+ cp = buf + sizeof (win_shortcut_hdr);
+ /* Creating an IDLIST */
+ hres = SHGetDesktopFolder (&psl);
+ if (SUCCEEDED (hres))
+ {
+ MultiByteToWideChar (CP_ACP, 0, w32topath, -1, wc_path,
+ CYG_MAX_PATH + 1);
+ hres = psl->ParseDisplayName (NULL, NULL, wc_path, NULL,
+ &pidl, NULL);
+ if (SUCCEEDED (hres))
+ {
+ shortcut_header->flags |= WSH_FLAG_IDLIST;
+ for (p = pidl; p->mkid.cb > 0;
+ p = (ITEMIDLIST *)((char *) p + p->mkid.cb))
+ ;
+ len = (char *) p - (char *) pidl + 2;
+ *(unsigned short *)cp = len;
+ memcpy (cp += 2, pidl, len);
+ cp += len;
+ CoTaskMemFree (pidl);
+ }
+ psl->Release ();
+ }
+ /* Creating a description */
+ *(unsigned short *)cp = len = strlen (topath);
+ memcpy (cp += 2, topath, len);
+ cp += len;
+ /* Creating a relpath */
+ if (reltopath[0])
+ {
+ *(unsigned short *)cp = len = strlen (reltopath);
+ memcpy (cp += 2, reltopath, len);
+ }
+ else
+ {
+ *(unsigned short *)cp = len = strlen (w32topath);
+ memcpy (cp += 2, w32topath, len);
+ }
+ cp += len;
+ success = WriteFile (h, buf, cp - buf, &written, NULL)
+ && written == (DWORD) (cp - buf);
}
else
{
@@ -2644,50 +2715,49 @@ done:
}
static bool
-cmp_shortcut_header (const char *file_header)
+cmp_shortcut_header (win_shortcut_hdr *file_header)
{
- create_shortcut_header ();
- return memcmp (shortcut_header, file_header, SHORTCUT_HDR_SIZE);
+ /* 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;
}
static int
check_shortcut (const char *path, DWORD fileattr, HANDLE h,
char *contents, int *error, unsigned *pflags)
{
- char file_header[SHORTCUT_HDR_SIZE];
+ win_shortcut_hdr *file_header;
+ char *buf, *cp;
unsigned short len;
int res = 0;
- DWORD got = 0;
+ DWORD size, got = 0;
/* Valid Cygwin & U/WIN shortcuts are R/O. */
if (!(fileattr & FILE_ATTRIBUTE_READONLY))
goto file_not_symlink;
- /* Read the files header information. This is used to check for a
- Cygwin or U/WIN shortcut or later to check for executable files. */
- if (!ReadFile (h, file_header, SHORTCUT_HDR_SIZE, &got, 0))
- {
- *error = EIO;
- goto close_it;
- }
- /* Check header if the shortcut is really created by Cygwin or U/WIN. */
- if (got != SHORTCUT_HDR_SIZE || cmp_shortcut_header (file_header))
+
+ if ((size = GetFileSize (h, NULL)) > 8192) /* Not a Cygwin symlink. */
goto file_not_symlink;
- /* Next 2 byte are USHORT, containing length of description entry. */
- if (!ReadFile (h, &len, sizeof len, &got, 0))
+ buf = (char *) alloca (size);
+ if (!ReadFile (h, buf, size, &got, 0))
{
*error = EIO;
goto close_it;
}
- if (got != sizeof len || len == 0 || len > CYG_MAX_PATH)
+ file_header = (win_shortcut_hdr *) buf;
+ if (got != size || !cmp_shortcut_header (file_header))
goto file_not_symlink;
- /* Now read description entry. */
- if (!ReadFile (h, contents, len, &got, 0))
- {
- *error = EIO;
- goto close_it;
- }
- if (got != len)
+ cp = buf + sizeof (win_shortcut_hdr);
+ if (file_header->flags & WSH_FLAG_IDLIST) /* Skip ITEMIDLIST */
+ cp += *(unsigned short *) cp + 2;
+ if ((len = *(unsigned short *) cp) == 0 || len > CYG_MAX_PATH)
goto file_not_symlink;
+ strncpy (contents, cp += 2, len);
contents[len] = '\0';
res = len;
if (res) /* It's a symlink. */
@@ -2696,7 +2766,7 @@ check_shortcut (const char *path, DWORD fileattr, HANDLE h,
file_not_symlink:
/* Not a symlink, see if executable. */
- if (!(*pflags & PATH_ALL_EXEC) && has_exec_chars (file_header, got))
+ if (!(*pflags & PATH_ALL_EXEC) && has_exec_chars ((const char *) &file_header, got))
*pflags |= PATH_EXEC;
close_it: