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>2007-10-10 20:54:09 +0400
committerCorinna Vinschen <corinna@vinschen.de>2007-10-10 20:54:09 +0400
commit044b62c7676d56bcabea5956cae38771eb5b2179 (patch)
treef81c4546538d0c5c7d728f476098c339829a70b5
parent4797f5bca35d9598ae6ac4a021ef37ba3f1a75e0 (diff)
* path.cc (struct symlink_info): Change size of contents member to
be able to keep SYMLINK_MAX sized strings. (symlink_worker): Rework for long path names. When writing windows shortcuts, store pathname additionally "hidden" after the actual shortcut data to workaround size limitations of the description field. (symlink_info::check_shortcut): Drop file name parameter. Drop max file size check. Use NT functions. Use appended full path if available, description otherwise. Check symlink string length for not exceeding SYMLINK_MAX. Don't close file here. (symlink_info::check_sysfile): Drop file name parameter. Use NT functions. Check symlink string length for not exceeding SYMLINK_MAX. Don't close file here. (symlink_info::check_reparse_point): Drop file name parameter. Drop useless length checks. Allow SYMLINK_MAX length symlink strings. Don't close file here. (symlink_info::posixify): Allow SYMLINK_MAX length symlink strings. (symlink_info::check): Turn around checking for symlink file attributes. Use NT functions. Close symlink file here. * include/limits.h (PATH_MAX): Define as 32760. Change comment. (SYMLINK_MAX): Define as PATH_MAX - 1.
-rw-r--r--winsup/cygwin/ChangeLog23
-rw-r--r--winsup/cygwin/include/limits.h7
-rw-r--r--winsup/cygwin/path.cc501
3 files changed, 301 insertions, 230 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 169302d44..b47e7529e 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,28 @@
2007-10-10 Corinna Vinschen <corinna@vinschen.de>
+ * path.cc (struct symlink_info): Change size of contents member to
+ be able to keep SYMLINK_MAX sized strings.
+ (symlink_worker): Rework for long path names. When writing windows
+ shortcuts, store pathname additionally "hidden" after the actual
+ shortcut data to workaround size limitations of the description field.
+ (symlink_info::check_shortcut): Drop file name parameter. Drop max
+ file size check. Use NT functions. Use appended full path if
+ available, description otherwise. Check symlink string length for
+ not exceeding SYMLINK_MAX. Don't close file here.
+ (symlink_info::check_sysfile): Drop file name parameter. Use NT
+ functions. Check symlink string length for not exceeding SYMLINK_MAX.
+ Don't close file here.
+ (symlink_info::check_reparse_point): Drop file name parameter. Drop
+ useless length checks. Allow SYMLINK_MAX length symlink strings.
+ Don't close file here.
+ (symlink_info::posixify): Allow SYMLINK_MAX length symlink strings.
+ (symlink_info::check): Turn around checking for symlink file attributes.
+ Use NT functions. Close symlink file here.
+ * include/limits.h (PATH_MAX): Define as 32760. Change comment.
+ (SYMLINK_MAX): Define as PATH_MAX - 1.
+
+2007-10-10 Corinna Vinschen <corinna@vinschen.de>
+
* fhandler_socket.cc (fhandler_socket::bind): Open file for deletion,
too. Don't write to file and especially don't close handle if file
couldn't be created. Set delete disposition if writing failed,
diff --git a/winsup/cygwin/include/limits.h b/winsup/cygwin/include/limits.h
index f7ae460e8..6dcf9caa1 100644
--- a/winsup/cygwin/include/limits.h
+++ b/winsup/cygwin/include/limits.h
@@ -318,9 +318,10 @@ details. */
#undef NAME_MAX
#define NAME_MAX 255
-/* Maximum length of a path */
+/* Maximum length of a path including trailing NUL.
+ (32767 - max. native NT path prefix) */
#undef PATH_MAX
-#define PATH_MAX 260
+#define PATH_MAX 32760
/* # of bytes in a pipe buf. This is the max # of bytes which can be
written to a pipe in one atomic operation. */
@@ -352,7 +353,7 @@ details. */
/* Maximum number of bytes in a symbolic link. */
#undef SYMLINK_MAX
-#define SYMLINK_MAX PATH_MAX
+#define SYMLINK_MAX (PATH_MAX - 1)
/* Runtime Increasable Values */
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 88add9a10..82be4df3e 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -89,7 +89,7 @@ static void backslashify (const char *, char *, int);
struct symlink_info
{
- char contents[CYG_MAX_PATH + 4];
+ char contents[SYMLINK_MAX + 1];
char *ext_here;
int extn;
unsigned pflags;
@@ -106,9 +106,9 @@ struct symlink_info
int set (char *path);
bool parse_device (const char *);
bool case_check (char *path);
- int check_sysfile (const char *path, HANDLE h);
- int check_shortcut (const char *path, HANDLE h);
- int check_reparse_point (const char *path, HANDLE h);
+ int check_sysfile (HANDLE h);
+ int check_shortcut (HANDLE h);
+ int check_reparse_point (HANDLE h);
int posixify (char *srcbuf);
bool set_error (int);
};
@@ -2874,16 +2874,17 @@ int
symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
bool isdevice)
{
- HANDLE h;
int res = -1;
- path_conv win32_path, win32_oldpath;
- char from[CYG_MAX_PATH + 5];
- char cwd[CYG_MAX_PATH], *cp = NULL, c = 0;
- char w32oldpath[CYG_MAX_PATH];
- char reloldpath[CYG_MAX_PATH] = { 0 };
- DWORD written;
+ size_t len;
+ path_conv win32_newpath, win32_oldpath;
+ char *buf, *cp;
SECURITY_ATTRIBUTES sa = sec_none_nih;
security_descriptor sd;
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ HANDLE fh;
+ FILE_BASIC_INFORMATION fbi;
/* POSIX says that empty 'newpath' is invalid input while empty
'oldpath' is valid -- it's symlink resolver job to verify if
@@ -2897,192 +2898,239 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
goto done;
}
- if (strlen (oldpath) >= CYG_MAX_PATH)
+ if (strlen (oldpath) > SYMLINK_MAX)
{
set_errno (ENAMETOOLONG);
goto done;
}
- win32_path.check (newpath, PC_SYM_NOFOLLOW,
- transparent_exe ? stat_suffixes : NULL);
- if (use_winsym && !win32_path.exists ())
+ len = strlen (newpath);
+ /* Trailing dirsep is a no-no. */
+ if (isdirsep (newpath[len - 1]))
+ {
+ set_errno (ENOENT);
+ goto done;
+ }
+ /* We need the normalized full path below. */
+ win32_newpath.check (newpath, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes);
+ if (use_winsym && !win32_newpath.exists ())
{
- strcpy (from, newpath);
- strcat (from, ".lnk");
- win32_path.check (from, PC_SYM_NOFOLLOW);
+ char *newplnk = (char *) alloca (len + 5);
+ stpcpy (stpcpy (newplnk, newpath), ".lnk");
+ win32_newpath.check (newplnk, PC_SYM_NOFOLLOW | PC_POSIX);
}
- if (win32_path.error)
+ if (win32_newpath.error)
{
- set_errno (win32_path.case_clash ? ECASECLASH : win32_path.error);
+ set_errno (win32_newpath.case_clash ? ECASECLASH : win32_newpath.error);
goto done;
}
- syscall_printf ("symlink (%s, %s)", oldpath, win32_path.get_win32 ());
+ syscall_printf ("symlink (%s, %S)", oldpath,
+ win32_newpath.get_nt_native_path ());
- if ((!isdevice && win32_path.exists ())
- || win32_path.is_auto_device ())
+ if ((!isdevice && win32_newpath.exists ())
+ || win32_newpath.is_auto_device ())
{
set_errno (EEXIST);
goto done;
}
- DWORD create_how;
- if (!use_winsym)
- create_how = CREATE_NEW;
- else if (isdevice)
+ if (use_winsym)
{
- strcpy (w32oldpath, oldpath);
- create_how = CREATE_ALWAYS;
- SetFileAttributes (win32_path.get_win32 (), FILE_ATTRIBUTE_NORMAL);
- }
- else
- {
- if (!isabspath (oldpath))
- {
- getcwd (cwd, CYG_MAX_PATH);
- if ((cp = strrchr (from, '/')) || (cp = strrchr (from, '\\')))
- {
- c = *cp;
- *cp = '\0';
- chdir (from);
- }
- backslashify (oldpath, reloldpath, 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 (reloldpath) == INVALID_FILE_ATTRIBUTES)
- {
- win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW,
- transparent_exe ? stat_suffixes : NULL);
- if (win32_oldpath.error != ENOENT)
- strcpy (use_winsym ? reloldpath : w32oldpath,
- win32_oldpath.get_win32 ());
- }
- else if (!use_winsym)
- strcpy (w32oldpath, reloldpath);
- if (use_winsym)
- {
- win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW,
- transparent_exe ? stat_suffixes : NULL);
- strcpy (w32oldpath, win32_oldpath.get_win32 ());
- }
- if (cp)
- {
- *cp = c;
- chdir (cwd);
- }
- }
- else
- {
- win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW,
- transparent_exe ? stat_suffixes : NULL);
- strcpy (w32oldpath, win32_oldpath.get_win32 ());
- }
- create_how = CREATE_NEW;
- }
+ ITEMIDLIST *pidl = NULL;
+ size_t full_len = 0;
+ unsigned short oldpath_len, desc_len, relpath_len, pidl_len = 0;
+ char desc[MAX_PATH + 1], *relpath;
- if (allow_ntsec && win32_path.has_acls ())
- set_security_attribute (S_IFLNK | STD_RBITS | STD_WBITS,
- &sa, sd);
-
- h = CreateFile (win32_path.get_win32 (), GENERIC_WRITE, 0, &sa, create_how,
- FILE_ATTRIBUTE_NORMAL, 0);
- if (h == INVALID_HANDLE_VALUE)
- __seterrno ();
- else
- {
- bool success = false;
-
- if (use_winsym)
- {
- /* 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;
+ if (!isdevice)
+ {
+ /* First create an IDLIST to learn how big our shortcut is
+ going to be. */
IShellFolder *psl;
- WCHAR wc_path[CYG_MAX_PATH];
- 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))
+
+ /* The symlink target is relative to the directory in which
+ the symlink gets created, not relative to the cwd. Therefore
+ we have to mangle the path quite a bit before calling path_conv. */
+ if (!isabspath (oldpath))
{
- MultiByteToWideChar (CP_ACP, 0, w32oldpath, -1, wc_path,
- CYG_MAX_PATH);
- hres = psl->ParseDisplayName (NULL, NULL, wc_path, NULL,
- &pidl, NULL);
- if (SUCCEEDED (hres))
+ len = strrchr (win32_newpath.normalized_path, '/')
+ - win32_newpath.normalized_path + 1;
+ char *absoldpath = (char *) alloca (len + strlen (oldpath) + 1);
+ stpcpy (stpncpy (absoldpath, win32_newpath.normalized_path, len),
+ oldpath);
+ win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
+ }
+ else
+ win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
+ if (SUCCEEDED (SHGetDesktopFolder (&psl)))
+ {
+ WCHAR wc_path[win32_oldpath.get_wide_win32_path_len () + 1];
+ win32_oldpath.get_wide_win32_path (wc_path);
+ /* Amazing but true: Even though the ParseDisplayName method
+ takes a wide char path name, it does not understand the
+ Win32 prefix for long pathnames! So we have to tack off
+ the prefix and convert tyhe path to the "normal" syntax
+ for ParseDisplayName. I have no idea if it's able to take
+ long path names at all since I can't test it right now. */
+ WCHAR *wc = wc_path + 4;
+ if (!wcscmp (wc, L"UNC\\"))
+ *(wc += 2) = L'\\';
+ HRESULT res;
+ if (SUCCEEDED (res = psl->ParseDisplayName (NULL, NULL, wc, NULL,
+ &pidl, NULL)))
{
- shortcut_header->flags |= WSH_FLAG_IDLIST;
+ ITEMIDLIST *p;
+
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);
+ pidl_len = (char *) p - (char *) pidl + 2;
}
psl->Release ();
}
- /* Creating a description */
- *(unsigned short *)cp = len = strlen (oldpath);
- memcpy (cp += 2, oldpath, len);
- cp += len;
- /* Creating a relpath */
- if (reloldpath[0])
- {
- *(unsigned short *)cp = len = strlen (reloldpath);
- memcpy (cp += 2, reloldpath, len);
- }
- else
- {
- *(unsigned short *)cp = len = strlen (w32oldpath);
- memcpy (cp += 2, w32oldpath, len);
- }
- cp += len;
- success = WriteFile (h, buf, cp - buf, &written, NULL)
- && written == (DWORD) (cp - buf);
+ }
+ /* Compute size of shortcut file. */
+ full_len = sizeof (win_shortcut_hdr);
+ if (pidl_len)
+ full_len += sizeof (unsigned short) + pidl_len;
+ oldpath_len = strlen (oldpath);
+ /* Unfortunately the length of the description is restricted to a
+ length of MAX_PATH up to NT4, and to a length of 2000 bytes
+ since W2K. We don't want to add considerations for the different
+ lengths and even 2000 bytes is not enough for long path names.
+ So what we do here is to set the description to the POSIX path
+ only if the path is not longer than MAX_PATH characters. We
+ append the full path name after the regular shortcut data
+ (see below), which works fine with Windows Explorer as well
+ as older Cygwin versions (as long as the whole file isn't bigger
+ than 8K). The description field is only used for backward
+ compatibility to older Cygwin versions and those versions are
+ not capable of handling long path names anyway. */
+ desc_len = stpcpy (desc, oldpath_len > MAX_PATH
+ ? "[path too long]" : oldpath) - desc;
+ full_len += sizeof (unsigned short) + desc_len;
+ /* Devices get the oldpath string unchanged as relative path. */
+ if (isdevice)
+ {
+ relpath_len = oldpath_len;
+ stpcpy (relpath = (char *) alloca (relpath_len + 1), oldpath);
}
else
{
- /* This is the old technique creating a symlink. */
- char buf[sizeof (SYMLINK_COOKIE) + CYG_MAX_PATH + 10];
+ relpath_len = strlen (win32_oldpath.get_win32 ());
+ stpcpy (relpath = (char *) alloca (relpath_len + 1),
+ win32_oldpath.get_win32 ());
+ }
+ full_len += sizeof (unsigned short) + relpath_len;
+ full_len += sizeof (unsigned short) + oldpath_len;
+ /* 1 byte more for trailing 0 written by stpcpy. */
+ buf = (char *) alloca (full_len + 1);
+
+ /* Create shortcut header */
+ win_shortcut_hdr *shortcut_header = (win_shortcut_hdr *) buf;
+ 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);
+ if (pidl)
+ shortcut_header->flags |= WSH_FLAG_IDLIST;
+ shortcut_header->run = SW_NORMAL;
+ cp = buf + sizeof (win_shortcut_hdr);
+
+ /* Create IDLIST */
+ if (pidl)
+ {
+ *(unsigned short *)cp = pidl_len;
+ memcpy (cp += 2, pidl, pidl_len);
+ cp += pidl_len;
+ CoTaskMemFree (pidl);
+ }
- __small_sprintf (buf, "%s%s", SYMLINK_COOKIE, oldpath);
- DWORD len = strlen (buf) + 1;
+ /* Create description */
+ *(unsigned short *)cp = desc_len;
+ cp = stpcpy (cp += 2, desc);
- /* Note that the terminating nul is written. */
- success = WriteFile (h, buf, len, &written, NULL)
- || written != len;
+ /* Create relpath */
+ *(unsigned short *)cp = relpath_len;
+ cp = stpcpy (cp += 2, relpath);
- }
- if (success)
+ /* Append the POSIX path after the regular shortcut data for
+ the long path support. */
+ *(unsigned short *)cp = oldpath_len;
+ cp = stpcpy (cp += 2, oldpath);
+ }
+ else
+ {
+ /* This is the old technique creating a symlink. */
+ unsigned short oldpath_len = strlen (oldpath);
+ buf = (char *) alloca (sizeof (SYMLINK_COOKIE) + oldpath_len + 1);
+ /* Note that the terminating nul is written. */
+ cp = stpcpy (stpcpy (buf, SYMLINK_COOKIE), oldpath) + 1;
+ }
+
+ if (isdevice && win32_newpath.exists ())
+ {
+ status = NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES,
+ win32_newpath.get_object_attr (attr, sa),
+ &io, 0, FILE_OPEN_FOR_BACKUP_INTENT);
+ if (!NT_SUCCESS (status))
{
- CloseHandle (h);
- DWORD attr = use_winsym ? FILE_ATTRIBUTE_READONLY
- : FILE_ATTRIBUTE_SYSTEM;
- SetFileAttributes (win32_path.get_win32 (), attr);
-
- res = 0;
+ __seterrno_from_nt_status (status);
+ goto done;
}
- else
+ fbi.CreationTime.QuadPart = fbi.LastAccessTime.QuadPart
+ = fbi.LastWriteTime.QuadPart = fbi.ChangeTime.QuadPart = 0LL;
+ fbi.FileAttributes = FILE_ATTRIBUTE_NORMAL;
+ status = NtSetInformationFile (fh, &io, &fbi, sizeof fbi,
+ FileBasicInformation);
+ NtClose (fh);
+ if (!NT_SUCCESS (status))
{
- __seterrno ();
- CloseHandle (h);
- DeleteFileA (win32_path.get_win32 ());
+ __seterrno_from_nt_status (status);
+ goto done;
}
}
+ if (allow_ntsec && win32_newpath.has_acls ())
+ set_security_attribute (S_IFLNK | STD_RBITS | STD_WBITS,
+ &sa, sd);
+ status = NtCreateFile (&fh, DELETE | FILE_GENERIC_WRITE,
+ win32_newpath.get_object_attr (attr, sa),
+ &io, NULL, FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_VALID_FLAGS,
+ isdevice ? FILE_OVERWRITE_IF : FILE_CREATE,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ | FILE_NON_DIRECTORY_FILE
+ | FILE_OPEN_FOR_BACKUP_INTENT,
+ NULL, 0);
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ goto done;
+ }
+ status = NtWriteFile (fh, NULL, NULL, NULL, &io, buf, cp - buf, NULL, NULL);
+ if (NT_SUCCESS (status) && io.Information == (ULONG) (cp - buf))
+ {
+ fbi.CreationTime.QuadPart = fbi.LastAccessTime.QuadPart
+ = fbi.LastWriteTime.QuadPart = fbi.ChangeTime.QuadPart = 0LL;
+ fbi.FileAttributes = use_winsym ? FILE_ATTRIBUTE_READONLY
+ : FILE_ATTRIBUTE_SYSTEM;
+ status = NtSetInformationFile (fh, &io, &fbi, sizeof fbi,
+ FileBasicInformation);
+ if (!NT_SUCCESS (status))
+ debug_printf ("Setting attributes failed, status = %p", status);
+ res = 0;
+ }
+ else
+ {
+ __seterrno_from_nt_status (status);
+ FILE_DISPOSITION_INFORMATION fdi = { TRUE };
+ status = NtSetInformationFile (fh, &io, &fdi, sizeof fdi,
+ FileDispositionInformation);
+ if (!NT_SUCCESS (status))
+ debug_printf ("Setting delete dispostion failed, status = %p", status);
+ }
+ NtClose (fh);
done:
syscall_printf ("%d = symlink_worker (%s, %s, %d, %d)", res, oldpath,
@@ -3104,80 +3152,98 @@ cmp_shortcut_header (win_shortcut_hdr *file_header)
}
int
-symlink_info::check_shortcut (const char *path, HANDLE h)
+symlink_info::check_shortcut (HANDLE h)
{
win_shortcut_hdr *file_header;
char *buf, *cp;
unsigned short len;
int res = 0;
- DWORD size, got = 0;
+ DWORD size;
+ IO_STATUS_BLOCK io;
- if ((size = GetFileSize (h, NULL)) > 8192) /* Not a Cygwin symlink. */
- goto file_not_symlink;
+ size = GetFileSize (h, NULL);
buf = (char *) alloca (size + 1);
- if (!ReadFile (h, buf, size, &got, 0))
+ if (!NT_SUCCESS (NtReadFile (h, NULL, NULL, NULL,
+ &io, buf, size, NULL, NULL)))
{
set_error (EIO);
goto close_it;
}
file_header = (win_shortcut_hdr *) buf;
- if (got != size || !cmp_shortcut_header (file_header))
+ if (io.Information != size || !cmp_shortcut_header (file_header))
goto file_not_symlink;
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)
+ if (!(len = *(unsigned short *) cp))
goto file_not_symlink;
cp += 2;
- cp[len] = '\0';
/* Check if this is a device file - these start with the sequence :\\ */
if (strncmp (cp, ":\\", 2) == 0)
- res = strlen (strcpy (contents, cp)); /* Don't try to mess with device files */
+ res = strlen (strcpy (contents, cp)); /* Don't mess with device files */
else
- res = posixify (cp);
+ {
+ /* Has appended full path? If so, use it instead of description. */
+ unsigned short relpath_len = *(unsigned short *) (cp + len);
+ if (cp + len + 2 + relpath_len < buf + size)
+ {
+ cp += len + 2 + relpath_len;
+ len = *(unsigned short *) cp;
+ cp += 2;
+ }
+ if (len > SYMLINK_MAX)
+ goto file_not_symlink;
+ cp[len] = '\0';
+ res = posixify (cp);
+ }
if (res) /* It's a symlink. */
pflags = PATH_SYMLINK | PATH_LNK;
goto close_it;
file_not_symlink:
/* Not a symlink, see if executable. */
- if (!(pflags & PATH_ALL_EXEC) && has_exec_chars ((const char *) &file_header, got))
+ if (!(pflags & PATH_ALL_EXEC) && has_exec_chars ((const char *) &file_header, io.Information))
pflags |= PATH_EXEC;
close_it:
- CloseHandle (h);
return res;
}
int
-symlink_info::check_sysfile (const char *path, HANDLE h)
+symlink_info::check_sysfile (HANDLE h)
{
char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
- char srcbuf[CYG_MAX_PATH];
- DWORD got;
+ char srcbuf[SYMLINK_MAX + 2];
+ IO_STATUS_BLOCK io;
int res = 0;
- if (!ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
+ if (!NT_SUCCESS (NtReadFile (h, NULL, NULL, NULL, &io,
+ cookie_buf, sizeof (cookie_buf), NULL, NULL)))
{
debug_printf ("ReadFile1 failed");
set_error (EIO);
}
- else if (got == sizeof (cookie_buf)
+ else if (io.Information == sizeof (cookie_buf)
&& memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
{
/* It's a symlink. */
pflags = PATH_SYMLINK;
- res = ReadFile (h, srcbuf, CYG_MAX_PATH, &got, 0);
- if (!res)
+ if (!NT_SUCCESS (NtReadFile (h, NULL, NULL, NULL, &io,
+ srcbuf, SYMLINK_MAX + 2, NULL, NULL)))
{
debug_printf ("ReadFile2 failed");
set_error (EIO);
}
+ else if (io.Information > SYMLINK_MAX + 1)
+ {
+ debug_printf ("symlink string too long");
+ set_error (EIO);
+ }
else
res = posixify (srcbuf);
}
- else if (got == sizeof (cookie_buf)
+ else if (io.Information == sizeof (cookie_buf)
&& memcmp (cookie_buf, SOCKET_COOKIE, sizeof (cookie_buf)) == 0)
pflags |= PATH_SOCKET;
else
@@ -3185,44 +3251,32 @@ symlink_info::check_sysfile (const char *path, HANDLE h)
/* Not a symlink, see if executable. */
if (pflags & PATH_ALL_EXEC)
/* Nothing to do */;
- else if (has_exec_chars (cookie_buf, got))
+ else if (has_exec_chars (cookie_buf, io.Information))
pflags |= PATH_EXEC;
else
pflags |= PATH_NOTEXEC;
}
- syscall_printf ("%d = symlink.check_sysfile (%s, %s) (%p)",
- res, path, contents, pflags);
-
- CloseHandle (h);
return res;
}
int
-symlink_info::check_reparse_point (const char *path, HANDLE h)
+symlink_info::check_reparse_point (HANDLE h)
{
- int res = 0;
PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER)
alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
DWORD size;
- char srcbuf[CYG_MAX_PATH + 6];
+ char srcbuf[SYMLINK_MAX + 7];
if (!DeviceIoControl (h, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID) rp,
MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &size, NULL))
{
debug_printf ("DeviceIoControl(FSCTL_GET_REPARSE_POINT) failed, %E");
set_error (EIO);
- goto close_it;
+ return 0;
}
if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
{
- if (rp->SymbolicLinkReparseBuffer.SubstituteNameLength
- > 2 * (CYG_MAX_PATH + 6))
- {
- debug_printf ("Symlink name too long");
- set_error (EIO);
- goto close_it;
- }
- sys_wcstombs (srcbuf, CYG_MAX_PATH,
+ sys_wcstombs (srcbuf, SYMLINK_MAX + 1,
(WCHAR *)((char *)rp->SymbolicLinkReparseBuffer.PathBuffer
+ rp->SymbolicLinkReparseBuffer.SubstituteNameOffset),
rp->SymbolicLinkReparseBuffer.SubstituteNameLength / 2);
@@ -3234,26 +3288,16 @@ symlink_info::check_reparse_point (const char *path, HANDLE h)
if (rp->SymbolicLinkReparseBuffer.PrintNameLength == 0)
{
/* Likely a volume mount point. Not treated as symlink. */
- goto close_it;
- }
- if (rp->MountPointReparseBuffer.SubstituteNameLength
- > 2 * (CYG_MAX_PATH + 6))
- {
- debug_printf ("Symlink name too long");
- set_error (EIO);
- goto close_it;
+ return 0;
}
- sys_wcstombs (srcbuf, CYG_MAX_PATH,
+ sys_wcstombs (srcbuf, SYMLINK_MAX + 1,
(WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer
+ rp->MountPointReparseBuffer.SubstituteNameOffset),
rp->MountPointReparseBuffer.SubstituteNameLength / 2);
pflags = PATH_SYMLINK | PATH_REP;
fileattr &= ~FILE_ATTRIBUTE_DIRECTORY;
}
- res = posixify (srcbuf);
-close_it:
- CloseHandle (h);
- return res;
+ return posixify (srcbuf);
}
int
@@ -3297,7 +3341,7 @@ symlink_info::posixify (char *srcbuf)
slashify (srcbuf, contents, 0);
else /* Paths starting with \ are current drive relative. */
{
- char cvtbuf[CYG_MAX_PATH + 6];
+ char cvtbuf[SYMLINK_MAX + 1];
strncpy (cvtbuf, cygheap->cwd.win32, 2);
strcpy (cvtbuf + 2, srcbuf);
@@ -3524,6 +3568,7 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
{
FILE_BASIC_INFORMATION fbi;
NTSTATUS status;
+ IO_STATUS_BLOCK io;
error = 0;
get_nt_native_path (suffix.path, upath);
@@ -3561,7 +3606,6 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
UNICODE_STRING dirname, basename;
OBJECT_ATTRIBUTES dattr;
HANDLE dir;
- IO_STATUS_BLOCK io;
FILE_DIRECTORY_INFORMATION fdi;
RtlSplitUnicodePath (&upath, &dirname, &basename);
@@ -3624,9 +3668,10 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
== FILE_ATTRIBUTE_DIRECTORY)
goto file_not_symlink;
- /* Reparse points are potentially symlinks. */
- if (fileattr & FILE_ATTRIBUTE_REPARSE_POINT)
- sym_check = 3;
+ /* Windows shortcuts are potentially treated as symlinks. */
+ /* Valid Cygwin & U/WIN shortcuts are R/O. */
+ if ((fileattr & FILE_ATTRIBUTE_READONLY) && suffix.lnk_match ())
+ sym_check = 1;
/* This is the old Cygwin method creating symlinks: */
/* A symlink will have the `system' file attribute. */
@@ -3634,29 +3679,29 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
else if (fileattr & FILE_ATTRIBUTE_SYSTEM)
sym_check = 2;
- /* Windows shortcuts are potentially treated as symlinks. */
- /* Valid Cygwin & U/WIN shortcuts are R/O. */
- else if ((fileattr & FILE_ATTRIBUTE_READONLY) && suffix.lnk_match ())
- sym_check = 1;
+ /* Reparse points are potentially symlinks. */
+ else if (fileattr & FILE_ATTRIBUTE_REPARSE_POINT)
+ sym_check = 3;
if (!sym_check)
goto file_not_symlink;
- /* Open the file. */
-
- h = CreateFile (suffix.path, GENERIC_READ, FILE_SHARE_READ,
- &sec_none_nih, OPEN_EXISTING,
- sym_check == 3 ? FILE_FLAG_OPEN_REPARSE_POINT
- | FILE_FLAG_BACKUP_SEMANTICS
- : FILE_ATTRIBUTE_NORMAL, 0);
res = -1;
- if (h == INVALID_HANDLE_VALUE)
+
+ /* Open the file. */
+ status = NtOpenFile (&h, FILE_GENERIC_READ, &attr, &io,
+ FILE_SHARE_VALID_FLAGS,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ | FILE_OPEN_FOR_BACKUP_INTENT
+ | (sym_check == 3 ? FILE_OPEN_REPARSE_POINT : 0));
+ if (!NT_SUCCESS (status))
goto file_not_symlink;
switch (sym_check)
{
case 1:
- res = check_shortcut (suffix.path, h);
+ res = check_shortcut (h);
+ NtClose (h);
if (!res)
/* check more below */;
else if (contents[0] == ':' && contents[1] == '\\' && parse_device (contents))
@@ -3671,12 +3716,14 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
fileattr = INVALID_FILE_ATTRIBUTES;
continue; /* in case we're going to tack *another* .lnk on this filename. */
case 2:
- res = check_sysfile (suffix.path, h);
+ res = check_sysfile (h);
+ NtClose (h);
if (!res)
goto file_not_symlink;
break;
case 3:
- res = check_reparse_point (suffix.path, h);
+ res = check_reparse_point (h);
+ NtClose (h);
if (!res)
goto file_not_symlink;
break;