summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/ChangeLog10
-rw-r--r--winsup/cygwin/path.cc71
2 files changed, 57 insertions, 24 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index b7d80c0de..837178f89 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,15 @@
2008-04-02 Corinna Vinschen <corinna@vinschen.de>
+ * path.cc (symlink_info::check_reparse_point): Use NtFsControlFile
+ to read reparse points.
+ (enum shortcut_t): New type.
+ (symlink_info::check): Convert sym_check to shortcut_t. Use shortcut_t
+ enum values throughout. Check reparse point before checking for
+ sysfile shortcut. Open reparse points with READ_CONTROL only to
+ accommodate special Vista reparse points. Add comments.
+
+2008-04-02 Corinna Vinschen <corinna@vinschen.de>
+
* flock.cc (get_lock_parent_dir): Drop call to NtOpenDirectoryObject
and utilize OBJ_OPENIF flag in call to NtCreateDirectoryObject.
(inode_t::inode_t): Ditto. Same for NtOpenMutant/NtCreateMutant.
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index f92bf8fe7..b9191e252 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -3487,15 +3487,19 @@ symlink_info::check_sysfile (HANDLE h)
int
symlink_info::check_reparse_point (HANDLE h)
{
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER)
alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
- DWORD size;
char srcbuf[SYMLINK_MAX + 7];
- if (!DeviceIoControl (h, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID) rp,
- MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &size, NULL))
+ status = NtFsControlFile (h, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT,
+ NULL, 0, (LPVOID) rp,
+ MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+ if (!NT_SUCCESS (status))
{
- debug_printf ("DeviceIoControl(FSCTL_GET_REPARSE_POINT) failed, %E");
+ debug_printf ("NtFsControlFile(FSCTL_GET_REPARSE_POINT) failed, %p",
+ status);
set_error (EIO);
return 0;
}
@@ -3774,6 +3778,13 @@ symlink_info::parse_device (const char *contents)
Return -1 on error, 0 if PATH is not a symlink, or the length
stored into BUF if PATH is a symlink. */
+enum shortcut_t {
+ is_no_symlink,
+ is_shortcut_symlink,
+ is_reparse_symlink,
+ is_sysfile_symlink
+};
+
int
symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
{
@@ -3896,9 +3907,9 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
|| (opt & PC_SYM_IGNORE))
goto file_not_symlink;
- int sym_check;
+ shortcut_t sym_check;
- sym_check = 0;
+ sym_check = is_no_symlink;
if ((fileattr & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT))
== FILE_ATTRIBUTE_DIRECTORY)
@@ -3907,35 +3918,45 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
/* 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;
+ sym_check = is_shortcut_symlink;
+
+ /* Reparse points are potentially symlinks. This check must be
+ performed before checking the SYSTEM attribute for sysfile
+ symlinks, since reparse points can have this flag set, too.
+ For instance, Vista starts to create a couple of reparse points
+ with SYSTEM and HIDDEN flags set. */
+ else if (fileattr & FILE_ATTRIBUTE_REPARSE_POINT)
+ sym_check = is_reparse_symlink;
/* This is 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). */
else if (fileattr & FILE_ATTRIBUTE_SYSTEM)
- sym_check = 2;
-
- /* Reparse points are potentially symlinks. */
- else if (fileattr & FILE_ATTRIBUTE_REPARSE_POINT)
- sym_check = 3;
+ sym_check = is_sysfile_symlink;
- if (!sym_check)
+ if (sym_check == is_no_symlink)
goto file_not_symlink;
res = -1;
- /* 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));
+ /* Open the file. Opening reparse points must not use GENERIC_READ.
+ The reason is that Vista starts to create a couple of reparse
+ points for backward compatibility, hidden system files, explicitely
+ denying everyone FILE_READ_DATA access. */
+ status = NtOpenFile (&h,
+ sym_check == is_reparse_symlink
+ ? READ_CONTROL : FILE_GENERIC_READ,
+ &attr, &io, FILE_SHARE_VALID_FLAGS,
+ FILE_OPEN_FOR_BACKUP_INTENT
+ | (sym_check == is_reparse_symlink
+ ? FILE_OPEN_REPARSE_POINT
+ : FILE_SYNCHRONOUS_IO_NONALERT));
if (!NT_SUCCESS (status))
goto file_not_symlink;
switch (sym_check)
{
- case 1:
+ case is_shortcut_symlink:
res = check_shortcut (h);
NtClose (h);
if (!res)
@@ -3951,18 +3972,20 @@ 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 (h);
+ case is_reparse_symlink:
+ res = check_reparse_point (h);
NtClose (h);
if (!res)
goto file_not_symlink;
break;
- case 3:
- res = check_reparse_point (h);
+ case is_sysfile_symlink:
+ res = check_sysfile (h);
NtClose (h);
if (!res)
goto file_not_symlink;
break;
+ default: /* Make gcc happy. Won't happen. */
+ goto file_not_symlink;
}
break;