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:
-rw-r--r--winsup/cygwin/ChangeLog36
-rw-r--r--winsup/cygwin/Makefile.in2
-rw-r--r--winsup/cygwin/autoload.cc34
-rw-r--r--winsup/cygwin/dir.cc19
-rw-r--r--winsup/cygwin/fhandler.cc5
-rw-r--r--winsup/cygwin/path.cc349
-rw-r--r--winsup/cygwin/security.cc12
-rw-r--r--winsup/cygwin/spawn.cc1
-rw-r--r--winsup/cygwin/syscalls.cc15
9 files changed, 403 insertions, 70 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 73fd3a24d..13a5cf15f 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,39 @@
+Wed Feb 21 22:41:00 2001 Corinna Vinschen <corinna@vinschen.de>
+
+ * Makefile.in: Add `-lshell32 -luuid' to link pass for new-cygwin1.dll.
+ * autoload.cc: Add LoadDLLinitfunc for ole32.dll.
+ Add LoadDLLfuncEx statements for CoInitialize@4, CoUninitialize@0
+ and CoCreateInstance@20.
+ * dir.cc (dir_suffixes): New datastructure.
+ (readdir): Check for R/O *.lnk files to hide the suffix.
+ (opendir): Use `dir_suffixes' in path conversion.
+ (rmdir): Ditto.
+ * fhandler.cc (fhandler_disk_file::fstat): Add S_IFLNK flag
+ before calling `get_file_attribute'. Take FILE_ATTRIBUTE_READONLY
+ into account only if the file is no symlink.
+ * path.cc (inner_suffixes): New datastructure.
+ (SYMLINKATTR): Eliminated.
+ (path_conv::check): Use `inner_suffixes' on inner path components.
+ (shortcut_header): New global static variable.
+ (shortcut_initalized): Ditto.
+ (create_shortcut_header): New function.
+ (cmp_shortcut_header): Ditto.
+ (symlink): Create symlinks by creating windows shortcuts. Preserve
+ the old code.
+ (symlink_info::check_shortcut): New method.
+ (symlink_info::check_sysfile): Ditto.
+ (symlink_info::check): Check for shortcuts. Move code reading
+ old system attribute symlinks into symlink_info::check_sysfile().
+ (chdir): Use `dir_suffixes' in path conversion.
+ * security.cc (get_file_attribute): Check for S_IFLNK flag.
+ Force 0777 permissions then.
+ * spawn.cc (std_suffixes): Add ".lnk" suffix.
+ * syscalls.cc (_unlink): Use `inner_suffixes' in path conversion.
+ Check for shortcut symlinks to eliminate R/O attribute before
+ calling DeleteFile().
+ (stat_suffixes): Add ".lnk" suffix.
+ (stat_worker): Force 0777 permissions if file is a symlink.
+
2001-02-21 Egor Duda <deo@logos-m.ru>
* sigproc.cc (getsem): Make semaphore always non-inheritable.
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index 18dbdc7c0..547b94727 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -190,7 +190,7 @@ new-$(LIB_NAME): $(LIB_NAME)
new-$(DLL_NAME): $(DLL_OFILES) $(DEF_FILE) $(DLL_IMPORTS) $(LIBC) $(LIBM) Makefile winver_stamp
$(CXX) $(CXXFLAGS) -nostdlib -Wl,-shared -o $@ -e $(DLL_ENTRY) $(DEF_FILE) $(DLL_OFILES) version.o \
- winver.o $(DLL_IMPORTS) $(MALLOC_OBJ) $(LIBM) $(LIBC) -lgcc -lstdc++
+ winver.o $(DLL_IMPORTS) $(MALLOC_OBJ) $(LIBM) $(LIBC) -lgcc -lstdc++ -lshell32 -luuid
dll_ofiles: $(DLL_OFILES)
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 00ee37b2c..bd035e397 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -90,6 +90,13 @@ LoadDLLinitfunc (advapi32)
LoadDLLinitfunc (netapi32)
{
HANDLE h;
+ static NO_COPY LONG here = -1L;
+
+ while (InterlockedIncrement (&here))
+ {
+ InterlockedDecrement (&here);
+ Sleep (0);
+ }
if ((h = LoadLibrary ("netapi32.dll")) != NULL)
netapi32_handle = h;
@@ -197,6 +204,28 @@ LoadDLLinitfunc (iphlpapi)
return 0;
}
+LoadDLLinitfunc (ole32)
+{
+ HANDLE h;
+ static NO_COPY LONG here = -1L;
+
+ while (InterlockedIncrement (&here))
+ {
+ InterlockedDecrement (&here);
+ Sleep (0);
+ }
+
+ if (ole32_handle)
+ /* nothing to do */;
+ else if ((h = LoadLibrary ("ole32.dll")) != NULL)
+ ole32_handle = h;
+ else if (!ole32_handle)
+ api_fatal ("could not load ole32.dll, %E");
+
+ InterlockedDecrement (&here);
+ return 0;
+}
+
static void __stdcall dummy_autoload (void) __attribute__ ((unused));
static void __stdcall
dummy_autoload (void)
@@ -339,5 +368,10 @@ LoadDLLfuncEx (WSASocketA, 24, ws2_32, 1)
LoadDLLinit (iphlpapi)
LoadDLLfuncEx (GetIfTable, 12, iphlpapi, 1)
LoadDLLfuncEx (GetIpAddrTable, 12, iphlpapi, 1)
+
+LoadDLLinit (ole32)
+LoadDLLfunc (CoInitialize, 4, ole32)
+LoadDLLfunc (CoUninitialize, 0, ole32)
+LoadDLLfunc (CoCreateInstance, 20, ole32)
}
}
diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc
index a14b44f8f..b4b93da20 100644
--- a/winsup/cygwin/dir.cc
+++ b/winsup/cygwin/dir.cc
@@ -59,6 +59,13 @@ writable_directory (const char *file)
#endif
}
+suffix_info dir_suffixes[] =
+{
+ suffix_info ("", 1),
+ suffix_info (".lnk", 1),
+ suffix_info (NULL)
+};
+
/* opendir: POSIX 5.1.2.1 */
extern "C" DIR *
opendir (const char *dirname)
@@ -68,7 +75,7 @@ opendir (const char *dirname)
DIR *res = 0;
struct stat statbuf;
- path_conv real_dirname (dirname, PC_SYM_FOLLOW | PC_FULL);
+ path_conv real_dirname (dirname, PC_SYM_FOLLOW | PC_FULL, dir_suffixes);
if (real_dirname.error)
{
@@ -174,6 +181,14 @@ readdir (DIR * dir)
/* We get here if `buf' contains valid data. */
strcpy (dir->__d_dirent->d_name, buf.cFileName);
+ if (buf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
+ {
+ char *c = dir->__d_dirent->d_name;
+ int len = strlen (c);
+ if (!strcasecmp (c + len - 4, ".lnk"))
+ c[len - 4] = '\0';
+ }
+
/* Compute d_ino by combining filename hash with the directory hash
(which was stored in dir->__d_dirhash when opendir was called). */
if (buf.cFileName[0] == '.')
@@ -316,7 +331,7 @@ rmdir (const char *dir)
{
int res = -1;
- path_conv real_dir (dir, PC_SYM_NOFOLLOW);
+ path_conv real_dir (dir, PC_SYM_NOFOLLOW, dir_suffixes);
if (real_dir.error)
{
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index 1c9e600a8..fdd6e91f8 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -921,6 +921,8 @@ fhandler_disk_file::fstat (struct stat *buf)
directory. This is used, to set S_ISVTX, if needed. */
if (local.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
buf->st_mode |= S_IFDIR;
+ if (get_symlink_p ())
+ buf->st_mode |= S_IFLNK;
if (!get_file_attribute (has_acls (),
get_win32_name (),
&buf->st_mode,
@@ -928,7 +930,8 @@ fhandler_disk_file::fstat (struct stat *buf)
&buf->st_gid))
{
/* If read-only attribute is set, modify ntsec return value */
- if (local.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
+ if ((local.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
+ && !get_symlink_p ())
buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
buf->st_mode &= ~S_IFMT;
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 20553920c..2b7b1eb53 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -57,6 +57,10 @@ details. */
#include <errno.h>
#include <ctype.h>
#include <winioctl.h>
+#include <wingdi.h>
+#include <winuser.h>
+#include <winnls.h>
+#include <winnetwk.h>
#include <sys/cygwin.h>
#include <cygwin/version.h>
#include "cygerrno.h"
@@ -70,6 +74,9 @@ details. */
#include "registry.h"
#include "security.h"
#include <assert.h>
+#include <shlobj.h>
+#include <objidl.h>
+#include <objbase.h>
static int normalize_win32_path (const char *src, char *dst);
static void slashify (const char *src, char *dst, int trailing_slash_p);
@@ -87,19 +94,25 @@ struct symlink_info
int is_symlink;
int error;
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);
};
+/* These suffixes are the only ones allowed in inner path components. */
+suffix_info inner_suffixes[] =
+{
+ suffix_info ("", 1),
+ suffix_info (".lnk", 1),
+ suffix_info (NULL)
+};
+
cwdstuff cygcwd; /* The current working directory. */
#define path_prefix_p(p1, p2, l1) \
((cyg_tolower(*(p1))==cyg_tolower(*(p2))) && \
path_prefix_p_(p1, p2, l1))
-#define SYMLINKATTR(x) \
- (((x) & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) == \
- FILE_ATTRIBUTE_SYSTEM)
-
/* Determine if path prefix matches current cygdrive */
#define iscygdrive(path) \
(path_prefix_p (mount_table->cygdrive, (path), mount_table->cygdrive_len))
@@ -264,7 +277,7 @@ path_conv::check (const char *src, unsigned opt,
class if we're working on an inner component of the path */
if (component)
{
- suff = NULL;
+ suff = inner_suffixes;
sym.pflags = 0;
}
else
@@ -2182,6 +2195,35 @@ endmntent (FILE *)
/********************** 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. */
extern "C"
@@ -2191,7 +2233,17 @@ symlink (const char *topath, const char *frompath)
HANDLE h;
int res = -1;
+#if 0
path_conv win32_path (frompath, PC_SYM_NOFOLLOW);
+#else
+ char from[MAX_PATH];
+ unsigned short len = strlen (frompath);
+ strcpy (from, frompath);
+ if (len <= 4 || strcasecmp (from + len - 4, ".lnk"))
+ strcpy (from + len, ".lnk");
+ path_conv win32_path (from, PC_SYM_NOFOLLOW);
+#endif
+
if (win32_path.error)
{
set_errno (win32_path.error);
@@ -2224,20 +2276,17 @@ symlink (const char *topath, const char *frompath)
__seterrno ();
else
{
+ DWORD written;
+#if 0
+ /* This is the old technique creating a symlink.
+ Preserved to have a fallback. */
char buf[sizeof (SYMLINK_COOKIE) + MAX_PATH + 10];
__small_sprintf (buf, "%s%s", SYMLINK_COOKIE, topath);
DWORD len = strlen (buf) + 1;
/* Note that the terminating nul is written. */
- DWORD written;
- if (!WriteFile (h, buf, len, &written, NULL) || written != len)
- {
- __seterrno ();
- CloseHandle (h);
- DeleteFileA (win32_path.get_win32 ());
- }
- else
+ if (WriteFile (h, buf, len, &written, NULL) || written != len)
{
CloseHandle (h);
set_file_attribute (win32_path.has_acls (),
@@ -2246,6 +2295,36 @@ symlink (const char *topath, const char *frompath)
SetFileAttributesA (win32_path.get_win32 (), FILE_ATTRIBUTE_SYSTEM);
res = 0;
}
+#else
+ create_shortcut_header ();
+ path_conv win32_topath (topath, PC_SYM_NOFOLLOW);
+ len = strlen (topath);
+ unsigned short win_len = strlen (win32_topath.get_win32 ());
+ if (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, win32_topath.get_win32 (), win_len, &written, NULL)
+ && written == win_len)
+ {
+ CloseHandle (h);
+ set_file_attribute (win32_path.has_acls (),
+ win32_path.get_win32 (),
+ S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
+ SetFileAttributesA (win32_path.get_win32 (), FILE_ATTRIBUTE_READONLY);
+ res = 0;
+ }
+#endif
+ else
+ {
+ __seterrno ();
+ CloseHandle (h);
+ DeleteFileA (win32_path.get_win32 ());
+ }
}
done:
@@ -2283,6 +2362,177 @@ next_suffix (char *ext_here, const suffix_info *&suffixes)
return 0;
}
+int
+symlink_info::check_shortcut (const char *path, DWORD fileattr, HANDLE h)
+{
+ 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];
+ DWORD got;
+ int res = 0;
+
+ if (! ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
+ {
+ debug_printf ("ReadFile1 failed");
+ error = EIO;
+ }
+ else if (got == sizeof (cookie_buf)
+ && memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
+ {
+ /* It's a symlink. */
+ pflags = PATH_SYMLINK;
+
+ res = ReadFile (h, contents, MAX_PATH + 1, &got, 0);
+ if (!res)
+ {
+ debug_printf ("ReadFile2 failed");
+ error = EIO;
+ }
+ else
+ {
+ /* Versions prior to b16 stored several trailing
+ NULs with the path (to fill the path out to 1024
+ chars). Current versions only store one trailing
+ NUL. The length returned is the path without
+ *any* trailing NULs. We also have to handle (or
+ at least not die from) corrupted paths. */
+ if (memchr (contents, 0, got) != NULL)
+ res = strlen (contents);
+ else
+ res = got;
+ }
+ }
+ else if (got == sizeof (cookie_buf)
+ && memcmp (cookie_buf, SOCKET_COOKIE, sizeof (cookie_buf)) == 0)
+ pflags |= PATH_SOCKET;
+ else
+ {
+ /* Not a symlink, see if executable. */
+ if (!(pflags & PATH_ALL_EXEC) && has_exec_chars (cookie_buf, got))
+ pflags |= PATH_EXEC;
+ }
+ syscall_printf ("%d = symlink.check_sysfile (%s, %s) (%p)",
+ res, path, contents, pflags);
+ return res;
+}
+
/* Check if PATH is a symlink. PATH must be a valid Win32 path name.
If PATH is a symlink, put the value of the symlink--the file to
@@ -2340,9 +2590,22 @@ symlink_info::check (const char *in_path, const suffix_info *suffixes)
continue;
}
+ int sym_check = 0;
+
+ if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
+ goto file_not_symlink;
+
+ /* Windows shortcuts are treated as symlinks. */
+ if (!strcasecmp (path + strlen (path) - 4, ".lnk"))
+ sym_check = 1;
+
+ /* The old Cygwin method creating symlinks: */
/* A symlink will have the `system' file attribute. */
/* Only files can be symlinks (which can be symlinks to directories). */
- if (!(pflags & PATH_SYMLINK) && !SYMLINKATTR (fileattr))
+ if (fileattr & FILE_ATTRIBUTE_SYSTEM)
+ sym_check = 2;
+
+ if (!sym_check && !(pflags & PATH_SYMLINK))
goto file_not_symlink;
/* Open the file. */
@@ -2352,54 +2615,15 @@ symlink_info::check (const char *in_path, const suffix_info *suffixes)
res = -1;
if (h == INVALID_HANDLE_VALUE)
goto file_not_symlink;
- else
+ else if (sym_check == 1 && !(res = check_shortcut (path, fileattr, h)))
{
- char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
- DWORD got;
-
- if (! ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
- error = EIO;
- else if (got == sizeof (cookie_buf)
- && memcmp (cookie_buf, SYMLINK_COOKIE,
- sizeof (cookie_buf)) == 0)
- {
- /* It's a symlink. */
- pflags = PATH_SYMLINK;
-
- res = ReadFile (h, contents, MAX_PATH + 1, &got, 0);
- if (!res)
- error = EIO;
- else
- {
- /* Versions prior to b16 stored several trailing
- NULs with the path (to fill the path out to 1024
- chars). Current versions only store one trailing
- NUL. The length returned is the path without
- *any* trailing NULs. We also have to handle (or
- at least not die from) corrupted paths. */
- if (memchr (contents, 0, got) != NULL)
- res = strlen (contents);
- else
- res = got;
- }
- }
- else if (got == sizeof (cookie_buf)
- && memcmp (cookie_buf, SOCKET_COOKIE,
- sizeof (cookie_buf)) == 0)
- {
- pflags |= PATH_SOCKET;
- goto close_and_return;
- }
- else
- {
- /* Not a symlink, see if executable. */
- if (!(pflags & PATH_ALL_EXEC) &&
- has_exec_chars (cookie_buf, got))
- pflags |= PATH_EXEC;
- close_and_return:
- CloseHandle (h);
- goto file_not_symlink;
- }
+ CloseHandle (h);
+ goto file_not_symlink;
+ }
+ else if (sym_check == 2 && !(res = check_sysfile (path, fileattr, h)))
+ {
+ CloseHandle (h);
+ goto file_not_symlink;
}
CloseHandle (h);
@@ -2553,8 +2777,9 @@ int
chdir (const char *dir)
{
MALLOC_CHECK;
+ extern suffix_info dir_suffixes[];
syscall_printf ("dir %s", dir);
- path_conv path (dir, PC_FULL | PC_SYM_FOLLOW);
+ path_conv path (dir, PC_FULL | PC_SYM_FOLLOW, dir_suffixes);
if (path.error)
{
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc
index 34ffc02fe..0f1a52dae 100644
--- a/winsup/cygwin/security.cc
+++ b/winsup/cygwin/security.cc
@@ -808,8 +808,15 @@ int
get_file_attribute (int use_ntsec, const char *file,
int *attribute, uid_t *uidret, gid_t *gidret)
{
+ int res;
+
if (use_ntsec && allow_ntsec)
- return get_nt_attribute (file, attribute, uidret, gidret);
+ {
+ res = get_nt_attribute (file, attribute, uidret, gidret);
+ if (attribute && (*attribute & S_IFLNK) == S_IFLNK)
+ *attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
+ return res;
+ }
if (uidret)
*uidret = getuid ();
@@ -819,8 +826,7 @@ get_file_attribute (int use_ntsec, const char *file,
if (!attribute)
return 0;
- int res = NTReadEA (file, ".UNIXATTR",
- (char *) attribute, sizeof (*attribute));
+ res = NTReadEA (file, ".UNIXATTR", (char *) attribute, sizeof (*attribute));
/* symlinks are everything for everyone!*/
if ((*attribute & S_IFLNK) == S_IFLNK)
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index cb30d6be7..507dfa563 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -41,6 +41,7 @@ details. */
static suffix_info std_suffixes[] =
{
suffix_info (".exe", 1), suffix_info ("", 1),
+ suffix_info (".lnk", 1),
suffix_info (".com"), suffix_info (".cmd"),
suffix_info (".bat"), suffix_info (".dll"),
suffix_info (NULL)
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index d5bb510ee..efe2c69ea 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -65,10 +65,11 @@ close_all_files (void)
extern "C" int
_unlink (const char *ourname)
{
+ extern suffix_info inner_suffixes[];
int res = -1;
sigframe thisframe (mainthread);
- path_conv win32_name (ourname, PC_SYM_NOFOLLOW | PC_FULL);
+ path_conv win32_name (ourname, PC_SYM_NOFOLLOW | PC_FULL, inner_suffixes);
if (win32_name.error)
{
@@ -94,6 +95,15 @@ _unlink (const char *ourname)
goto done;
}
+ /* Check for shortcut as symlink condition. */
+ if (atts != 0xffffffff && atts & FILE_ATTRIBUTE_READONLY)
+ {
+ int len = strlen (win32_name.get_win32 ());
+ if (len > 4 && !strcasecmp (win32_name.get_win32 () + len - 4, ".lnk"))
+ SetFileAttributes (win32_name.get_win32 (),
+ win32_name.file_attributes () & ~FILE_ATTRIBUTE_READONLY);
+ }
+
for (int i = 0; i < 2; i++)
{
if (DeleteFile (win32_name))
@@ -1021,6 +1031,7 @@ suffix_info stat_suffixes[] =
{
suffix_info ("", 1),
suffix_info (".exe", 1),
+ suffix_info (".lnk", 1),
suffix_info (NULL)
};
@@ -1135,6 +1146,8 @@ stat_worker (const char *caller, const char *name, struct stat *buf,
buf->st_mode |= STD_RBITS | STD_XBITS;
if ((atts & FILE_ATTRIBUTE_READONLY) == 0)
buf->st_mode |= STD_WBITS;
+ if (real_path.issymlink ())
+ buf->st_mode |= S_IRWXU | S_IRWXG | S_IRWXO;
get_file_attribute (FALSE, real_path.get_win32 (),
NULL, &buf->st_uid, &buf->st_gid);
}