* shortcut.c: New file. Provides a C interface to reading of
Windows shortcuts to avoid compiler flag `-fvtable-thunks'. * shortcut.h: Ditto. * Makefile.in: Add shortcut.o to DLL_OFILES. * cygerrno.h: Provide a C interface to `geterrno_from_win_error' for using in shortcut.c. * errno.cc (geterrno_from_win_error): Define as extern "C". * path.cc (struct symlink_info): Remove methods `check_shortcut' and `check_sysfile'. (shortcut_header): Move to shortcut.c. (shortcut_initalized): Ditto. (create_shortcut_header): Ditto. (cmp_shortcut_header): Ditto. (symlink_info::check_shortcut): Ditto. Reorganize as a plain C function. (symlink_info::check_sysfile): Redefine as a global function using the same parameter list as `check_shortcut' for clearness. (symlink_info::check): Change parameter list for calls to `check_shortcut' and `check_sysfile'.
This commit is contained in:
parent
957059c831
commit
79e56091c9
@ -1,3 +1,24 @@
|
|||||||
|
Thu Feb 22 13:38:00 2001 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
|
* shortcut.c: New file. Provides a C interface to reading of
|
||||||
|
Windows shortcuts to avoid compiler flag `-fvtable-thunks'.
|
||||||
|
* shortcut.h: Ditto.
|
||||||
|
* Makefile.in: Add shortcut.o to DLL_OFILES.
|
||||||
|
* cygerrno.h: Provide a C interface to `geterrno_from_win_error' for
|
||||||
|
using in shortcut.c.
|
||||||
|
* errno.cc (geterrno_from_win_error): Define as extern "C".
|
||||||
|
* path.cc (struct symlink_info): Remove methods `check_shortcut' and
|
||||||
|
`check_sysfile'.
|
||||||
|
(shortcut_header): Move to shortcut.c.
|
||||||
|
(shortcut_initalized): Ditto.
|
||||||
|
(create_shortcut_header): Ditto.
|
||||||
|
(cmp_shortcut_header): Ditto.
|
||||||
|
(symlink_info::check_shortcut): Ditto. Reorganize as a plain C function.
|
||||||
|
(symlink_info::check_sysfile): Redefine as a global function using the
|
||||||
|
same parameter list as `check_shortcut' for clearness.
|
||||||
|
(symlink_info::check): Change parameter list for calls to
|
||||||
|
`check_shortcut' and `check_sysfile'.
|
||||||
|
|
||||||
Thu Feb 22 12:04:00 2001 Corinna Vinschen <corinna@vinschen.de>
|
Thu Feb 22 12:04:00 2001 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* fhandler.cc (fhandler_disk_file::open): Use `inner_suffixes' when
|
* fhandler.cc (fhandler_disk_file::open): Use `inner_suffixes' when
|
||||||
|
@ -124,7 +124,8 @@ DLL_OFILES:=assert.o autoload.o cygheap.o dcrt0.o debug.o delqueue.o dir.o \
|
|||||||
miscfuncs.o mmap.o \
|
miscfuncs.o mmap.o \
|
||||||
net.o ntea.o passwd.o path.o pinfo.o pipe.o poll.o pthread.o regexp.o \
|
net.o ntea.o passwd.o path.o pinfo.o pipe.o poll.o pthread.o regexp.o \
|
||||||
regerror.o regsub.o registry.o resource.o scandir.o security.o select.o \
|
regerror.o regsub.o registry.o resource.o scandir.o security.o select.o \
|
||||||
shared.o signal.o sigproc.o smallprint.o spawn.o strace.o strsep.o \
|
shared.o \
|
||||||
|
shortcut.o signal.o sigproc.o smallprint.o spawn.o strace.o strsep.o \
|
||||||
sync.o syscalls.o sysconf.o syslog.o termios.o thread.o times.o tty.o \
|
sync.o syscalls.o sysconf.o syslog.o termios.o thread.o times.o tty.o \
|
||||||
uinfo.o uname.o wait.o window.o \
|
uinfo.o uname.o wait.o window.o \
|
||||||
$(EXTRA_DLL_OFILES) $(EXTRA_OFILES) $(MT_SAFE_OBJECTS)
|
$(EXTRA_DLL_OFILES) $(EXTRA_OFILES) $(MT_SAFE_OBJECTS)
|
||||||
|
@ -8,9 +8,20 @@ This software is a copyrighted work licensed under the terms of the
|
|||||||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||||
details. */
|
details. */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int __stdcall geterrno_from_win_error (DWORD code, int deferrno) __attribute__ ((regparm(2)));
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
void __stdcall seterrno_from_win_error (const char *file, int line, DWORD code) __attribute__ ((regparm(3)));
|
void __stdcall seterrno_from_win_error (const char *file, int line, DWORD code) __attribute__ ((regparm(3)));
|
||||||
void __stdcall seterrno (const char *, int line) __attribute__ ((regparm(2)));
|
void __stdcall seterrno (const char *, int line) __attribute__ ((regparm(2)));
|
||||||
int __stdcall geterrno_from_win_error (DWORD code, int deferrno) __attribute__ ((regparm(2)));
|
|
||||||
|
|
||||||
#define __seterrno() seterrno (__FILE__, __LINE__)
|
#define __seterrno() seterrno (__FILE__, __LINE__)
|
||||||
#define __seterrno_from_win_error(val) seterrno_from_win_error (__FILE__, __LINE__, val)
|
#define __seterrno_from_win_error(val) seterrno_from_win_error (__FILE__, __LINE__, val)
|
||||||
@ -32,3 +43,5 @@ class save_errno
|
|||||||
|
|
||||||
extern const char *__sp_fn;
|
extern const char *__sp_fn;
|
||||||
extern int __sp_ln;
|
extern int __sp_ln;
|
||||||
|
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
@ -110,7 +110,7 @@ errmap[] =
|
|||||||
{ 0, NULL, 0}
|
{ 0, NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
int __stdcall
|
extern "C" int __stdcall
|
||||||
geterrno_from_win_error (DWORD code, int deferrno)
|
geterrno_from_win_error (DWORD code, int deferrno)
|
||||||
{
|
{
|
||||||
for (int i = 0; errmap[i].w != 0; ++i)
|
for (int i = 0; errmap[i].w != 0; ++i)
|
||||||
|
@ -74,9 +74,7 @@ details. */
|
|||||||
#include "registry.h"
|
#include "registry.h"
|
||||||
#include "security.h"
|
#include "security.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <shlobj.h>
|
#include "shortcut.h"
|
||||||
#include <objidl.h>
|
|
||||||
#include <objbase.h>
|
|
||||||
|
|
||||||
static int normalize_win32_path (const char *src, char *dst);
|
static int normalize_win32_path (const char *src, char *dst);
|
||||||
static void slashify (const char *src, char *dst, int trailing_slash_p);
|
static void slashify (const char *src, char *dst, int trailing_slash_p);
|
||||||
@ -94,8 +92,6 @@ struct symlink_info
|
|||||||
int is_symlink;
|
int is_symlink;
|
||||||
int error;
|
int error;
|
||||||
symlink_info (): known_suffix (NULL), contents (buf + MAX_PATH + 1) {}
|
symlink_info (): known_suffix (NULL), contents (buf + MAX_PATH + 1) {}
|
||||||
int check_shortcut (const char *, DWORD, HANDLE);
|
|
||||||
int check_sysfile (const char *, DWORD, HANDLE);
|
|
||||||
int check (const char *path, const suffix_info *suffixes);
|
int check (const char *path, const suffix_info *suffixes);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2195,35 +2191,6 @@ endmntent (FILE *)
|
|||||||
|
|
||||||
/********************** Symbolic Link Support **************************/
|
/********************** Symbolic Link Support **************************/
|
||||||
|
|
||||||
/* The header written to a shortcut by Cygwin or U/WIN. */
|
|
||||||
#define SHORTCUT_HDR_SIZE 76
|
|
||||||
static char shortcut_header[SHORTCUT_HDR_SIZE];
|
|
||||||
static BOOL shortcut_initalized = FALSE;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL
|
|
||||||
cmp_shortcut_header (const char *file_header)
|
|
||||||
{
|
|
||||||
create_shortcut_header ();
|
|
||||||
return memcmp (shortcut_header, file_header, SHORTCUT_HDR_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a symlink from FROMPATH to TOPATH. */
|
/* Create a symlink from FROMPATH to TOPATH. */
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
@ -2362,127 +2329,9 @@ next_suffix (char *ext_here, const suffix_info *&suffixes)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
symlink_info::check_shortcut (const char *path, DWORD fileattr, HANDLE h)
|
check_sysfile (const char *path, DWORD fileattr, HANDLE h,
|
||||||
{
|
char *contents, int *error, unsigned *pflags)
|
||||||
HRESULT hres;
|
|
||||||
IShellLink *psl = NULL;
|
|
||||||
IPersistFile *ppf = NULL;
|
|
||||||
WCHAR wc_path[MAX_PATH];
|
|
||||||
char full_path[MAX_PATH];
|
|
||||||
WIN32_FIND_DATA wfd;
|
|
||||||
DWORD len = 0;
|
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
/* Initialize COM library. */
|
|
||||||
CoInitialize (NULL);
|
|
||||||
|
|
||||||
/* Get a pointer to the IShellLink interface. */
|
|
||||||
hres = CoCreateInstance (CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
|
||||||
IID_IShellLink, (void **)&psl);
|
|
||||||
if (FAILED (hres))
|
|
||||||
{
|
|
||||||
debug_printf ("CoCreateInstance failed");
|
|
||||||
goto close_it;
|
|
||||||
}
|
|
||||||
/* Get a pointer to the IPersistFile interface. */
|
|
||||||
hres = psl->QueryInterface (IID_IPersistFile, (void **)&ppf);
|
|
||||||
if (FAILED (hres))
|
|
||||||
{
|
|
||||||
debug_printf ("QueryInterface failed");
|
|
||||||
goto close_it;
|
|
||||||
}
|
|
||||||
/* Load the shortcut. */
|
|
||||||
MultiByteToWideChar(CP_ACP, 0, path, -1, wc_path, MAX_PATH);
|
|
||||||
hres = ppf->Load (wc_path, STGM_READ);
|
|
||||||
if (FAILED (hres))
|
|
||||||
{
|
|
||||||
debug_printf ("Load failed");
|
|
||||||
goto close_it;
|
|
||||||
}
|
|
||||||
/* Try the description (containing a POSIX path) first. */
|
|
||||||
if (fileattr & FILE_ATTRIBUTE_READONLY)
|
|
||||||
{
|
|
||||||
/* An additional check is needed to prove if it's a shortcut
|
|
||||||
really created by Cygwin or U/WIN. */
|
|
||||||
char file_header[SHORTCUT_HDR_SIZE];
|
|
||||||
DWORD got;
|
|
||||||
|
|
||||||
if (! ReadFile (h, file_header, SHORTCUT_HDR_SIZE, &got, 0))
|
|
||||||
{
|
|
||||||
debug_printf ("ReadFile failed");
|
|
||||||
error = EIO;
|
|
||||||
goto close_it_dont_set_error;
|
|
||||||
}
|
|
||||||
if (got == SHORTCUT_HDR_SIZE && !cmp_shortcut_header (file_header))
|
|
||||||
{
|
|
||||||
hres = psl->GetDescription (contents, MAX_PATH);
|
|
||||||
if (FAILED (hres))
|
|
||||||
{
|
|
||||||
debug_printf ("GetDescription failed");
|
|
||||||
goto close_it;
|
|
||||||
}
|
|
||||||
len = strlen (contents);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* No description or not R/O: Check the "official" path. */
|
|
||||||
if (len == 0)
|
|
||||||
{
|
|
||||||
/* Convert to full path (easy way) */
|
|
||||||
if ((path[0] == '\\' && path[1] == '\\')
|
|
||||||
|| (_toupper (path[0]) >= 'A' && _toupper (path[0]) <= 'Z'
|
|
||||||
&& path[1] == ':'))
|
|
||||||
len = 0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
len = GetCurrentDirectory (MAX_PATH, full_path);
|
|
||||||
if (path[0] == '\\')
|
|
||||||
len = 2;
|
|
||||||
else if (full_path[len - 1] != '\\')
|
|
||||||
strcpy (full_path + len++, "\\");
|
|
||||||
}
|
|
||||||
strcpy (full_path + len, path);
|
|
||||||
debug_printf ("full_path = <%s>", full_path);
|
|
||||||
/* Set relative path inside of IShellLink interface. */
|
|
||||||
hres = psl->SetRelativePath (full_path, 0);
|
|
||||||
if (FAILED (hres))
|
|
||||||
{
|
|
||||||
debug_printf ("SetRelativePath failed");
|
|
||||||
goto close_it;
|
|
||||||
}
|
|
||||||
/* Get the path to the shortcut target. */
|
|
||||||
hres = psl->GetPath (contents, MAX_PATH, &wfd, 0);
|
|
||||||
if (FAILED(hres))
|
|
||||||
{
|
|
||||||
debug_printf ("GetPath failed");
|
|
||||||
goto close_it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* It's a symlink. */
|
|
||||||
pflags = PATH_SYMLINK;
|
|
||||||
res = strlen (contents);
|
|
||||||
|
|
||||||
close_it:
|
|
||||||
if (FAILED (hres))
|
|
||||||
error = geterrno_from_win_error (HRESULT_CODE (hres), EACCES);
|
|
||||||
|
|
||||||
close_it_dont_set_error:
|
|
||||||
/* Release the pointer to IPersistFile. */
|
|
||||||
if (ppf)
|
|
||||||
ppf->Release();
|
|
||||||
/* Release the pointer to IShellLink. */
|
|
||||||
if (psl)
|
|
||||||
psl->Release();
|
|
||||||
/* Uninitialize COM library. */
|
|
||||||
CoUninitialize ();
|
|
||||||
|
|
||||||
syscall_printf ("%d = symlink.check_shortcut (%s, %s) (%p)",
|
|
||||||
res, path, contents, pflags);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
symlink_info::check_sysfile (const char *path, DWORD fileattr, HANDLE h)
|
|
||||||
{
|
{
|
||||||
char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
|
char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
|
||||||
DWORD got;
|
DWORD got;
|
||||||
@ -2491,19 +2340,19 @@ symlink_info::check_sysfile (const char *path, DWORD fileattr, HANDLE h)
|
|||||||
if (! ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
|
if (! ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
|
||||||
{
|
{
|
||||||
debug_printf ("ReadFile1 failed");
|
debug_printf ("ReadFile1 failed");
|
||||||
error = EIO;
|
*error = EIO;
|
||||||
}
|
}
|
||||||
else if (got == sizeof (cookie_buf)
|
else if (got == sizeof (cookie_buf)
|
||||||
&& memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
|
&& memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
|
||||||
{
|
{
|
||||||
/* It's a symlink. */
|
/* It's a symlink. */
|
||||||
pflags = PATH_SYMLINK;
|
*pflags = PATH_SYMLINK;
|
||||||
|
|
||||||
res = ReadFile (h, contents, MAX_PATH + 1, &got, 0);
|
res = ReadFile (h, contents, MAX_PATH + 1, &got, 0);
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
debug_printf ("ReadFile2 failed");
|
debug_printf ("ReadFile2 failed");
|
||||||
error = EIO;
|
*error = EIO;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2521,15 +2370,13 @@ symlink_info::check_sysfile (const char *path, DWORD fileattr, HANDLE h)
|
|||||||
}
|
}
|
||||||
else if (got == sizeof (cookie_buf)
|
else if (got == sizeof (cookie_buf)
|
||||||
&& memcmp (cookie_buf, SOCKET_COOKIE, sizeof (cookie_buf)) == 0)
|
&& memcmp (cookie_buf, SOCKET_COOKIE, sizeof (cookie_buf)) == 0)
|
||||||
pflags |= PATH_SOCKET;
|
*pflags |= PATH_SOCKET;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Not a symlink, see if executable. */
|
/* Not a symlink, see if executable. */
|
||||||
if (!(pflags & PATH_ALL_EXEC) && has_exec_chars (cookie_buf, got))
|
if (!(*pflags & PATH_ALL_EXEC) && has_exec_chars (cookie_buf, got))
|
||||||
pflags |= PATH_EXEC;
|
*pflags |= PATH_EXEC;
|
||||||
}
|
}
|
||||||
syscall_printf ("%d = symlink.check_sysfile (%s, %s) (%p)",
|
|
||||||
res, path, contents, pflags);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2615,12 +2462,16 @@ symlink_info::check (const char *in_path, const suffix_info *suffixes)
|
|||||||
res = -1;
|
res = -1;
|
||||||
if (h == INVALID_HANDLE_VALUE)
|
if (h == INVALID_HANDLE_VALUE)
|
||||||
goto file_not_symlink;
|
goto file_not_symlink;
|
||||||
else if (sym_check == 1 && !(res = check_shortcut (path, fileattr, h)))
|
else if (sym_check == 1
|
||||||
|
&& !(res = check_shortcut (path, fileattr, h,
|
||||||
|
contents, &error, &pflags)))
|
||||||
{
|
{
|
||||||
CloseHandle (h);
|
CloseHandle (h);
|
||||||
goto file_not_symlink;
|
goto file_not_symlink;
|
||||||
}
|
}
|
||||||
else if (sym_check == 2 && !(res = check_sysfile (path, fileattr, h)))
|
else if (sym_check == 2 &&
|
||||||
|
!(res = check_sysfile (path, fileattr, h,
|
||||||
|
contents, &error, &pflags)))
|
||||||
{
|
{
|
||||||
CloseHandle (h);
|
CloseHandle (h);
|
||||||
goto file_not_symlink;
|
goto file_not_symlink;
|
||||||
|
171
winsup/cygwin/shortcut.c
Normal file
171
winsup/cygwin/shortcut.c
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
/* shortcut.c: Read shortcuts. This part of the code must be in C because
|
||||||
|
the C++ interface to COM doesn't work without -fvtable-thunk
|
||||||
|
which is too dangerous to use.
|
||||||
|
|
||||||
|
Copyright 2001 Red Hat, Inc.
|
||||||
|
|
||||||
|
This file is part of Cygwin.
|
||||||
|
|
||||||
|
This software is a copyrighted work licensed under the terms of the
|
||||||
|
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||||
|
details. */
|
||||||
|
|
||||||
|
#include "winsup.h"
|
||||||
|
#include <shlobj.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "cygerrno.h"
|
||||||
|
#include "shortcut.h"
|
||||||
|
|
||||||
|
/* This is needed to avoid including path.h which is a pure C++ header. */
|
||||||
|
#define PATH_SYMLINK MOUNT_SYMLINK
|
||||||
|
|
||||||
|
#define debug_printf(x) strcpy (contents, x)
|
||||||
|
|
||||||
|
char shortcut_header[SHORTCUT_HDR_SIZE];
|
||||||
|
BOOL shortcut_initalized = FALSE;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL
|
||||||
|
cmp_shortcut_header (const char *file_header)
|
||||||
|
{
|
||||||
|
create_shortcut_header ();
|
||||||
|
return memcmp (shortcut_header, file_header, SHORTCUT_HDR_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
check_shortcut (const char *path, DWORD fileattr, HANDLE h,
|
||||||
|
char *contents, int *error, unsigned *pflags)
|
||||||
|
{
|
||||||
|
HRESULT hres;
|
||||||
|
IShellLink *psl = NULL;
|
||||||
|
IPersistFile *ppf = NULL;
|
||||||
|
WCHAR wc_path[MAX_PATH];
|
||||||
|
char full_path[MAX_PATH];
|
||||||
|
WIN32_FIND_DATA wfd;
|
||||||
|
DWORD len = 0;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
/* Initialize COM library. */
|
||||||
|
CoInitialize (NULL);
|
||||||
|
|
||||||
|
/* Get a pointer to the IShellLink interface. */
|
||||||
|
hres = CoCreateInstance (&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
||||||
|
&IID_IShellLink, (void **)&psl);
|
||||||
|
if (FAILED (hres))
|
||||||
|
{
|
||||||
|
debug_printf ("CoCreateInstance failed");
|
||||||
|
goto close_it;
|
||||||
|
}
|
||||||
|
/* Get a pointer to the IPersistFile interface. */
|
||||||
|
hres = psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile, (void **)&ppf);
|
||||||
|
if (FAILED (hres))
|
||||||
|
{
|
||||||
|
debug_printf ("QueryInterface failed");
|
||||||
|
goto close_it;
|
||||||
|
}
|
||||||
|
/* Load the shortcut. */
|
||||||
|
MultiByteToWideChar(CP_ACP, 0, path, -1, wc_path, MAX_PATH);
|
||||||
|
hres = ppf->lpVtbl->Load (ppf, wc_path, STGM_READ);
|
||||||
|
if (FAILED (hres))
|
||||||
|
{
|
||||||
|
debug_printf ("Load failed");
|
||||||
|
goto close_it;
|
||||||
|
}
|
||||||
|
/* Try the description (containing a POSIX path) first. */
|
||||||
|
if (fileattr & FILE_ATTRIBUTE_READONLY)
|
||||||
|
{
|
||||||
|
/* An additional check is needed to prove if it's a shortcut
|
||||||
|
really created by Cygwin or U/WIN. */
|
||||||
|
char file_header[SHORTCUT_HDR_SIZE];
|
||||||
|
DWORD got;
|
||||||
|
|
||||||
|
if (! ReadFile (h, file_header, SHORTCUT_HDR_SIZE, &got, 0))
|
||||||
|
{
|
||||||
|
debug_printf ("ReadFile failed");
|
||||||
|
*error = EIO;
|
||||||
|
goto close_it_dont_set_error;
|
||||||
|
}
|
||||||
|
if (got == SHORTCUT_HDR_SIZE && !cmp_shortcut_header (file_header))
|
||||||
|
{
|
||||||
|
hres = psl->lpVtbl->GetDescription (psl, contents, MAX_PATH);
|
||||||
|
if (FAILED (hres))
|
||||||
|
{
|
||||||
|
debug_printf ("GetDescription failed");
|
||||||
|
goto close_it;
|
||||||
|
}
|
||||||
|
len = strlen (contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* No description or not R/O: Check the "official" path. */
|
||||||
|
if (len == 0)
|
||||||
|
{
|
||||||
|
/* Convert to full path (easy way) */
|
||||||
|
if ((path[0] == '\\' && path[1] == '\\')
|
||||||
|
|| (_toupper (path[0]) >= 'A' && _toupper (path[0]) <= 'Z'
|
||||||
|
&& path[1] == ':'))
|
||||||
|
len = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
len = GetCurrentDirectory (MAX_PATH, full_path);
|
||||||
|
if (path[0] == '\\')
|
||||||
|
len = 2;
|
||||||
|
else if (full_path[len - 1] != '\\')
|
||||||
|
strcpy (full_path + len++, "\\");
|
||||||
|
}
|
||||||
|
strcpy (full_path + len, path);
|
||||||
|
/* Set relative path inside of IShellLink interface. */
|
||||||
|
hres = psl->lpVtbl->SetRelativePath (psl, full_path, 0);
|
||||||
|
if (FAILED (hres))
|
||||||
|
{
|
||||||
|
debug_printf ("SetRelativePath failed");
|
||||||
|
goto close_it;
|
||||||
|
}
|
||||||
|
/* Get the path to the shortcut target. */
|
||||||
|
hres = psl->lpVtbl->GetPath (psl, contents, MAX_PATH, &wfd, 0);
|
||||||
|
if (FAILED(hres))
|
||||||
|
{
|
||||||
|
debug_printf ("GetPath failed");
|
||||||
|
goto close_it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* It's a symlink. */
|
||||||
|
*pflags = PATH_SYMLINK;
|
||||||
|
res = strlen (contents);
|
||||||
|
|
||||||
|
close_it:
|
||||||
|
if (FAILED (hres))
|
||||||
|
*error = geterrno_from_win_error (HRESULT_CODE (hres), EACCES);
|
||||||
|
|
||||||
|
close_it_dont_set_error:
|
||||||
|
/* Release the pointer to IPersistFile. */
|
||||||
|
if (ppf)
|
||||||
|
ppf->lpVtbl->Release(ppf);
|
||||||
|
/* Release the pointer to IShellLink. */
|
||||||
|
if (psl)
|
||||||
|
psl->lpVtbl->Release(psl);
|
||||||
|
/* Uninitialize COM library. */
|
||||||
|
CoUninitialize ();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
28
winsup/cygwin/shortcut.h
Normal file
28
winsup/cygwin/shortcut.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/* shortcut.h: Hader file for shortcut.c
|
||||||
|
|
||||||
|
Copyright 2001 Red Hat, Inc.
|
||||||
|
|
||||||
|
This file is part of Cygwin.
|
||||||
|
|
||||||
|
This software is a copyrighted work licensed under the terms of the
|
||||||
|
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||||
|
details. */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The header written to a shortcut by Cygwin or U/WIN. */
|
||||||
|
#define SHORTCUT_HDR_SIZE 76
|
||||||
|
|
||||||
|
extern char shortcut_header[];
|
||||||
|
extern BOOL shortcut_initalized;
|
||||||
|
|
||||||
|
extern void create_shortcut_header ();
|
||||||
|
|
||||||
|
int check_shortcut (const char *path, DWORD fileattr, HANDLE h,
|
||||||
|
char *contents, int *error, unsigned *pflags);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user