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>2006-10-31 14:40:47 +0300
committerCorinna Vinschen <corinna@vinschen.de>2006-10-31 14:40:47 +0300
commit9740f34d11c458fd7a07a025810422a6db1ad374 (patch)
treef534b30bf61b4392013eabe56906a053207a3acc
parent3ddf69712bc97460fe6b0e82379e0c1132dce866 (diff)
* fhandler_disk_file.cc (fhandler_base::fstat_by_handle): Drop
directory attribute for reparse points to avoid mistreating. (fhandler_base::fstat_by_name): Ditto. * path.cc (symlink_info::check_reparse_point): New method testing reparse points for symbolic links. (symlink_info::check_shortcut): Move file attribute tesat to calling function. (symlink_info::check): Add handling for reparse points. * path.h (enum path_types): Add PATH_REP to denote reparse point based symlinks. (path_conv::is_rep_symlink): New method. * syscalls.cc (unlink): Handle reparse points.
-rw-r--r--winsup/cygwin/ChangeLog15
-rw-r--r--winsup/cygwin/fhandler_disk_file.cc10
-rw-r--r--winsup/cygwin/path.cc87
-rw-r--r--winsup/cygwin/path.h2
-rw-r--r--winsup/cygwin/syscalls.cc12
5 files changed, 112 insertions, 14 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 1487544c6..fddfd6bf7 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,18 @@
+2006-10-31 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler_disk_file.cc (fhandler_base::fstat_by_handle): Drop
+ directory attribute for reparse points to avoid mistreating.
+ (fhandler_base::fstat_by_name): Ditto.
+ * path.cc (symlink_info::check_reparse_point): New method testing
+ reparse points for symbolic links.
+ (symlink_info::check_shortcut): Move file attribute tesat to calling
+ function.
+ (symlink_info::check): Add handling for reparse points.
+ * path.h (enum path_types): Add PATH_REP to denote reparse point based
+ symlinks.
+ (path_conv::is_rep_symlink): New method.
+ * syscalls.cc (unlink): Handle reparse points.
+
2006-10-27 Corinna Vinschen <corinna@vinschen.de>
* shared.cc (open_shared): Drop useless attempt from 2006-08-11.
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index da358bd1d..f3b5ec03e 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -240,6 +240,8 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
/* If the change time is 0, it's a file system which doesn't
support a change timestamp. In that case use the LastWriteTime
entry, as in other calls to fstat_helper. */
+ if (pc.is_rep_symlink ())
+ pfai->BasicInformation.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
pc.file_attributes (pfai->BasicInformation.FileAttributes);
return fstat_helper (buf,
pfai->BasicInformation.ChangeTime.QuadPart ?
@@ -275,7 +277,11 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
local.dwFileAttributes = DWORD (pc);
}
else
- pc.file_attributes (local.dwFileAttributes);
+ {
+ if (pc.is_rep_symlink ())
+ local.dwFileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
+ pc.file_attributes (local.dwFileAttributes);
+ }
return fstat_helper (buf,
local.ftLastWriteTime, /* see fstat_helper comment */
local.ftLastAccessTime,
@@ -306,6 +312,8 @@ fhandler_base::fstat_by_name (struct __stat64 *buf)
else if ((handle = FindFirstFile (pc, &local)) != INVALID_HANDLE_VALUE)
{
FindClose (handle);
+ if (pc.is_rep_symlink ())
+ local.dwFileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
pc.file_attributes (local.dwFileAttributes);
res = fstat_helper (buf,
local.ftLastWriteTime, /* see fstat_helper comment */
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index cfe0735c5..f32cfb4c8 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -104,6 +104,7 @@ struct symlink_info
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);
bool set_error (int);
};
@@ -2996,10 +2997,6 @@ symlink_info::check_shortcut (const char *path, HANDLE h)
int res = 0;
DWORD size, got = 0;
- /* Valid Cygwin & U/WIN shortcuts are R/O. */
- if (!(fileattr & FILE_ATTRIBUTE_READONLY))
- goto file_not_symlink;
-
if ((size = GetFileSize (h, NULL)) > 8192) /* Not a Cygwin symlink. */
goto file_not_symlink;
buf = (char *) alloca (size);
@@ -3033,7 +3030,6 @@ close_it:
return res;
}
-
int
symlink_info::check_sysfile (const char *path, HANDLE h)
{
@@ -3093,6 +3089,61 @@ symlink_info::check_sysfile (const char *path, HANDLE h)
return res;
}
+int
+symlink_info::check_reparse_point (const char *path, HANDLE h)
+{
+ int res = 0;
+ PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER)
+ alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+ DWORD size;
+
+ 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;
+ }
+ if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
+ {
+ if (rp->SymbolicLinkReparseBuffer.PrintNameLength > 2 * CYG_MAX_PATH)
+ {
+ debug_printf ("Symlink name too long");
+ set_error (EIO);
+ goto close_it;
+ }
+ res = sys_wcstombs (contents, CYG_MAX_PATH,
+ (WCHAR *)((char *)rp->SymbolicLinkReparseBuffer.PathBuffer
+ + rp->SymbolicLinkReparseBuffer.PrintNameOffset),
+ rp->SymbolicLinkReparseBuffer.PrintNameLength / 2);
+ pflags = PATH_SYMLINK | PATH_REP;
+ fileattr &= ~FILE_ATTRIBUTE_DIRECTORY;
+ }
+ else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ if (rp->SymbolicLinkReparseBuffer.PrintNameLength == 0)
+ {
+ /* Likely a volume mount point. Not treated as symlink. */
+ goto close_it;
+ }
+ if (rp->MountPointReparseBuffer.PrintNameLength > 2 * CYG_MAX_PATH)
+ {
+ debug_printf ("Symlink name too long");
+ set_error (EIO);
+ goto close_it;
+ }
+ res = sys_wcstombs (contents, CYG_MAX_PATH,
+ (WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer
+ + rp->MountPointReparseBuffer.PrintNameOffset),
+ rp->MountPointReparseBuffer.PrintNameLength / 2);
+ pflags = PATH_SYMLINK | PATH_REP;
+ fileattr &= ~FILE_ATTRIBUTE_DIRECTORY;
+ }
+close_it:
+ CloseHandle (h);
+ return res;
+}
+
enum
{
SCAN_BEG,
@@ -3337,26 +3388,35 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
sym_check = 0;
- if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
+ if ((fileattr & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT))
+ == FILE_ATTRIBUTE_DIRECTORY)
goto file_not_symlink;
- /* Windows shortcuts are treated as symlinks. */
- if (suffix.lnk_match ())
- sym_check = 1;
+ /* Reparse points are potentially symlinks. */
+ if (fileattr & FILE_ATTRIBUTE_REPARSE_POINT)
+ sym_check = 3;
/* 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). */
- if (fileattr & FILE_ATTRIBUTE_SYSTEM)
+ 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;
+
if (!sym_check)
goto file_not_symlink;
/* Open the file. */
h = CreateFile (suffix.path, GENERIC_READ, FILE_SHARE_READ,
- &sec_none_nih, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ &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)
goto file_not_symlink;
@@ -3383,6 +3443,11 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
if (!res)
goto file_not_symlink;
break;
+ case 3:
+ res = check_reparse_point (suffix.path, h);
+ if (!res)
+ goto file_not_symlink;
+ break;
}
break;
diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h
index b00adc76d..0b2decc0d 100644
--- a/winsup/cygwin/path.h
+++ b/winsup/cygwin/path.h
@@ -76,6 +76,7 @@ enum path_types
PATH_NO_ACCESS_CHECK = PC_NO_ACCESS_CHECK,
PATH_LNK = 0x01000000,
PATH_TEXT = 0x02000000,
+ PATH_REP = 0x04000000,
PATH_HAS_SYMLINKS = 0x10000000,
PATH_SOCKET = 0x40000000
};
@@ -163,6 +164,7 @@ class path_conv
}
int issymlink () const {return path_flags & PATH_SYMLINK;}
int is_lnk_symlink () const {return path_flags & PATH_LNK;}
+ int is_rep_symlink () const {return path_flags & PATH_REP;}
int isdevice () const {return dev.devn && dev.devn != FH_FS && dev.devn != FH_FIFO;}
int isfifo () const {return dev == FH_FIFO;}
int isspecial () const {return dev.devn && dev.devn != FH_FS;}
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 66839be95..eb07890a1 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -205,8 +205,11 @@ unlink (const char *ourname)
if (!win32_name.isremote () && wincap.has_delete_on_close ())
{
HANDLE h;
+ DWORD flags = FILE_FLAG_DELETE_ON_CLOSE;
+ if (win32_name.is_rep_symlink ())
+ flags |= FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS;
h = CreateFile (win32_name, 0, FILE_SHARE_READ, &sec_none_nih,
- OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0);
+ OPEN_EXISTING, flags, 0);
if (h != INVALID_HANDLE_VALUE)
{
if (wincap.has_hard_links () && setattrs)
@@ -229,7 +232,12 @@ unlink (const char *ourname)
}
/* Try a delete with attributes reset */
- if (DeleteFile (win32_name))
+ if (win32_name.is_rep_symlink () && RemoveDirectory (win32_name))
+ {
+ syscall_printf ("RemoveDirectory after CreateFile/CloseHandle succeeded");
+ goto ok;
+ }
+ else if (DeleteFile (win32_name))
{
syscall_printf ("DeleteFile after CreateFile/CloseHandle succeeded");
goto ok;