* 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.
This commit is contained in:
Corinna Vinschen 2001-02-21 21:49:37 +00:00
parent 5b2ea3a436
commit 10b06c5ee0
9 changed files with 403 additions and 70 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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)
{

View File

@ -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;

View File

@ -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)
{

View File

@ -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)

View File

@ -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)

View File

@ -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);
}