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:
Diffstat (limited to 'winsup/cygwin/path.cc')
-rw-r--r--winsup/cygwin/path.cc434
1 files changed, 327 insertions, 107 deletions
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index cfda6bb27..16571b12e 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -343,7 +343,7 @@ path_conv::add_ext_from_sym (symlink_info &sym)
static void __reg2 mkrelpath (char *dst, bool caseinsensitive);
-static void __stdcall
+static void __reg2
mkrelpath (char *path, bool caseinsensitive)
{
tmp_pathbuf tp;
@@ -527,7 +527,7 @@ getfileattr (const char *path, bool caseinsensitive) /* path has to be always ab
directory query. */
UNICODE_STRING dirname, basename;
HANDLE dir;
- FILE_BOTH_DIRECTORY_INFORMATION fdi;
+ FILE_BOTH_DIR_INFORMATION fdi;
RtlSplitUnicodePath (&upath, &dirname, &basename);
InitializeObjectAttributes (&attr, &dirname,
@@ -1213,11 +1213,10 @@ file_get_fnoi (HANDLE h, bool skip_network_open_inf,
status = skip_network_open_inf ? STATUS_INVALID_PARAMETER
: NtQueryInformationFile (h, &io, pfnoi, sizeof *pfnoi,
FileNetworkOpenInformation);
- if (status == STATUS_INVALID_PARAMETER || status == STATUS_NOT_IMPLEMENTED)
+ if (status == STATUS_INVALID_PARAMETER)
{
/* Apart from accessing Netapps, this also occurs when accessing SMB
- share root dirs hosted on NT4 (STATUS_INVALID_PARAMETER), or when
- accessing SMB share root dirs from NT4 (STATUS_NOT_IMPLEMENTED). */
+ share root dirs hosted on NT4. */
FILE_BASIC_INFORMATION fbi;
FILE_STANDARD_INFORMATION fsi;
@@ -1363,7 +1362,7 @@ normalize_win32_path (const char *src, char *dst, char *&tail)
/* nofinalslash: Remove trailing / and \ from SRC (except for the
first one). It is ok for src == dst. */
-void __stdcall
+void __reg2
nofinalslash (const char *src, char *dst)
{
int len = strlen (src);
@@ -1476,27 +1475,108 @@ conv_path_list (const char *src, char *dst, size_t size,
extern "C" int
symlink (const char *oldpath, const char *newpath)
{
- return symlink_worker (oldpath, newpath, allow_winsymlinks, false);
+ return symlink_worker (oldpath, newpath, false);
+}
+
+static int
+symlink_nfs (const char *oldpath, path_conv &win32_newpath)
+{
+ /* On NFS, create symlinks by calling NtCreateFile with an EA of type
+ NfsSymlinkTargetName containing ... the symlink target name. */
+ tmp_pathbuf tp;
+ PFILE_FULL_EA_INFORMATION pffei;
+ NTSTATUS status;
+ HANDLE fh;
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+
+ pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
+ pffei->NextEntryOffset = 0;
+ pffei->Flags = 0;
+ pffei->EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
+ char *EaValue = stpcpy (pffei->EaName, NFS_SYML_TARGET) + 1;
+ pffei->EaValueLength = sizeof (WCHAR) *
+ (sys_mbstowcs ((PWCHAR) EaValue, NT_MAX_PATH, oldpath) - 1);
+ status = NtCreateFile (&fh, FILE_WRITE_DATA | FILE_WRITE_EA | SYNCHRONIZE,
+ win32_newpath.get_object_attr (attr, sec_none_nih),
+ &io, NULL, FILE_ATTRIBUTE_SYSTEM,
+ FILE_SHARE_VALID_FLAGS, FILE_CREATE,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ | FILE_OPEN_FOR_BACKUP_INTENT,
+ pffei, NT_MAX_PATH * sizeof (WCHAR));
+ if (!NT_SUCCESS (status))
+ {
+ __seterrno_from_nt_status (status);
+ return -1;
+ }
+ NtClose (fh);
+ return 0;
+}
+
+static int
+symlink_native (const char *oldpath, path_conv &win32_newpath)
+{
+ tmp_pathbuf tp;
+ path_conv win32_oldpath;
+ PUNICODE_STRING final_oldpath, final_newpath;
+
+ if (isabspath (oldpath))
+ {
+ win32_oldpath.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
+ final_oldpath = win32_oldpath.get_nt_native_path ();
+ final_oldpath->Buffer[1] = L'\\';
+ }
+ else
+ {
+ /* 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. */
+ ssize_t len = strrchr (win32_newpath.normalized_path, '/')
+ - win32_newpath.normalized_path + 1;
+ char *absoldpath = tp.t_get ();
+ stpcpy (stpncpy (absoldpath, win32_newpath.normalized_path, len),
+ oldpath);
+ win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
+ UNICODE_STRING dirpath;
+ RtlSplitUnicodePath (win32_newpath.get_nt_native_path (), &dirpath, NULL);
+ final_oldpath = win32_oldpath.get_nt_native_path ();
+ final_oldpath->Buffer += dirpath.Length / sizeof (WCHAR);
+ }
+ /* If the symlink target doesn't exist, don't create native symlink.
+ Otherwise the directory flag in the symlink is potentially wrong
+ when the target comes into existence, and native tools will fail.
+ This is so screwball. This is no problem on AFS, fortunately. */
+ if (!win32_oldpath.exists () && !win32_oldpath.fs_is_afs ())
+ {
+ SetLastError (ERROR_FILE_NOT_FOUND);
+ return -1;
+ }
+ /* Convert native path to DOS UNC path. */
+ final_newpath = win32_newpath.get_nt_native_path ();
+ final_newpath->Buffer[1] = L'\\';
+ /* Try to create native symlink. */
+ if (!CreateSymbolicLinkW (final_newpath->Buffer, final_oldpath->Buffer,
+ win32_oldpath.isdir ()
+ ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0))
+ {
+ /* Repair native path, we still need it. */
+ final_newpath->Buffer[1] = L'?';
+ return -1;
+ }
+ return 0;
}
int
-symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
- bool isdevice)
+symlink_worker (const char *oldpath, const char *newpath, bool isdevice)
{
int res = -1;
size_t len;
- path_conv win32_newpath, win32_oldpath;
+ path_conv win32_newpath;
char *buf, *cp;
- SECURITY_ATTRIBUTES sa = sec_none_nih;
- OBJECT_ATTRIBUTES attr;
- IO_STATUS_BLOCK io;
- NTSTATUS status;
- HANDLE fh;
- ULONG access = DELETE | FILE_GENERIC_WRITE;
tmp_pathbuf tp;
unsigned check_opt;
- bool mk_winsym = use_winsym;
bool has_trailing_dirsep = false;
+ winsym_t wsym_type;
/* POSIX says that empty 'newpath' is invalid input while empty
'oldpath' is valid -- it's symlink resolver job to verify if
@@ -1528,11 +1608,35 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
check_opt = PC_SYM_NOFOLLOW | PC_POSIX | (isdevice ? PC_NOWARN : 0);
/* We need the normalized full path below. */
win32_newpath.check (newpath, check_opt, stat_suffixes);
+
+ /* Default symlink type is determined by global allow_winsymlinks variable.
+ Device files are always shortcuts. */
+ wsym_type = isdevice ? WSYM_lnk : allow_winsymlinks;
+ /* NFS has its own, dedicated way to create symlinks. */
+ if (win32_newpath.fs_is_nfs ())
+ wsym_type = WSYM_nfs;
/* MVFS doesn't handle the SYSTEM DOS attribute, but it handles the R/O
attribute. Therefore we create symlinks on MVFS always as shortcuts. */
- mk_winsym |= win32_newpath.fs_is_mvfs ();
+ else if (win32_newpath.fs_is_mvfs ())
+ wsym_type = WSYM_lnk;
+ /* AFS only supports native symlinks. */
+ else if (win32_newpath.fs_is_afs ())
+ {
+ /* Bail out if OS doesn't support native symlinks. */
+ if (wincap.max_sys_priv () < SE_CREATE_SYMBOLIC_LINK_PRIVILEGE)
+ {
+ set_errno (EPERM);
+ goto done;
+ }
+ wsym_type = WSYM_nativestrict;
+ }
+ /* Don't try native symlinks on filesystems not supporting reparse points. */
+ else if ((wsym_type == WSYM_native || wsym_type == WSYM_nativestrict)
+ && !(win32_newpath.fs_flags () & FILE_SUPPORTS_REPARSE_POINTS))
+ wsym_type = WSYM_sysfile;
- if (mk_winsym && !win32_newpath.exists ()
+ /* Attach .lnk suffix when shortcut is requested. */
+ if (wsym_type == WSYM_lnk && !win32_newpath.exists ()
&& (isdevice || !win32_newpath.fs_is_nfs ()))
{
char *newplnk = tp.c_get ();
@@ -1546,8 +1650,8 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
goto done;
}
- syscall_printf ("symlink (%s, %S)", oldpath,
- win32_newpath.get_nt_native_path ());
+ syscall_printf ("symlink (%s, %S) wsym_type %d", oldpath,
+ win32_newpath.get_nt_native_path (), wsym_type);
if ((!isdevice && win32_newpath.exists ())
|| win32_newpath.is_auto_device ())
@@ -1561,36 +1665,33 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
goto done;
}
- if (!isdevice && win32_newpath.fs_is_nfs ())
- {
- /* On NFS, create symlinks by calling NtCreateFile with an EA of type
- NfsSymlinkTargetName containing ... the symlink target name. */
- PFILE_FULL_EA_INFORMATION pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
- pffei->NextEntryOffset = 0;
- pffei->Flags = 0;
- pffei->EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
- char *EaValue = stpcpy (pffei->EaName, NFS_SYML_TARGET) + 1;
- pffei->EaValueLength = sizeof (WCHAR) *
- (sys_mbstowcs ((PWCHAR) EaValue, NT_MAX_PATH, oldpath) - 1);
- status = NtCreateFile (&fh, FILE_WRITE_DATA | FILE_WRITE_EA | SYNCHRONIZE,
- win32_newpath.get_object_attr (attr, sa),
- &io, NULL, FILE_ATTRIBUTE_SYSTEM,
- FILE_SHARE_VALID_FLAGS, FILE_CREATE,
- FILE_SYNCHRONOUS_IO_NONALERT
- | FILE_OPEN_FOR_BACKUP_INTENT,
- pffei, NT_MAX_PATH * sizeof (WCHAR));
- if (!NT_SUCCESS (status))
+ /* Handle NFS and native symlinks in their own functions. */
+ switch (wsym_type)
+ {
+ case WSYM_nfs:
+ res = symlink_nfs (oldpath, win32_newpath);
+ goto done;
+ case WSYM_native:
+ case WSYM_nativestrict:
+ res = symlink_native (oldpath, win32_newpath);
+ if (!res)
+ goto done;
+ /* Strictly native? Too bad. */
+ if (wsym_type == WSYM_nativestrict)
{
- __seterrno_from_nt_status (status);
+ __seterrno ();
goto done;
}
- NtClose (fh);
- res = 0;
- goto done;
+ /* Otherwise, fall back to default symlink type. */
+ wsym_type = WSYM_sysfile;
+ break;
+ default:
+ break;
}
- if (mk_winsym)
+ if (wsym_type == WSYM_lnk)
{
+ path_conv win32_oldpath;
ITEMIDLIST *pidl = NULL;
size_t full_len = 0;
unsigned short oldpath_len, desc_len, relpath_len, pidl_len = 0;
@@ -1605,11 +1706,11 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
/* 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))
- win32_oldpath.check (oldpath,
- PC_SYM_NOFOLLOW,
- stat_suffixes);
- else
+ if (isabspath (oldpath))
+ win32_oldpath.check (oldpath,
+ PC_SYM_NOFOLLOW,
+ stat_suffixes);
+ else
{
len = strrchr (win32_newpath.normalized_path, '/')
- win32_newpath.normalized_path + 1;
@@ -1650,12 +1751,11 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
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
+ length of 2000 bytes. 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
@@ -1679,7 +1779,7 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
full_len += sizeof (unsigned short) + oldpath_len;
/* 1 byte more for trailing 0 written by stpcpy. */
if (full_len < NT_MAX_PATH * sizeof (WCHAR))
- buf = (char *) tp.w_get ();
+ buf = tp.t_get ();
else
buf = (char *) alloca (full_len + 1);
@@ -1723,7 +1823,7 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
else
{
/* Default technique creating a symlink. */
- buf = (char *) tp.w_get ();
+ buf = tp.t_get ();
cp = stpcpy (buf, SYMLINK_COOKIE);
*(PWCHAR) cp = 0xfeff; /* BOM */
cp += 2;
@@ -1731,10 +1831,17 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
cp += sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR);
}
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ ULONG access;
+ HANDLE fh;
+
+ access = DELETE | FILE_GENERIC_WRITE;
if (isdevice && win32_newpath.exists ())
{
status = NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES,
- win32_newpath.get_object_attr (attr, sa),
+ win32_newpath.get_object_attr (attr, sec_none_nih),
&io, 0, FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
{
@@ -1760,7 +1867,8 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
so for now we don't request WRITE_DAC on remote drives. */
access |= READ_CONTROL | WRITE_DAC;
- status = NtCreateFile (&fh, access, win32_newpath.get_object_attr (attr, sa),
+ status = NtCreateFile (&fh, access,
+ win32_newpath.get_object_attr (attr, sec_none_nih),
&io, NULL, FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_VALID_FLAGS,
isdevice ? FILE_OVERWRITE_IF : FILE_CREATE,
@@ -1780,10 +1888,11 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
status = NtWriteFile (fh, NULL, NULL, NULL, &io, buf, cp - buf, NULL, NULL);
if (NT_SUCCESS (status) && io.Information == (ULONG) (cp - buf))
{
- status = NtSetAttributesFile (fh, mk_winsym ? FILE_ATTRIBUTE_READONLY
- : FILE_ATTRIBUTE_SYSTEM);
+ status = NtSetAttributesFile (fh, wsym_type == WSYM_lnk
+ ? FILE_ATTRIBUTE_READONLY
+ : FILE_ATTRIBUTE_SYSTEM);
if (!NT_SUCCESS (status))
- debug_printf ("Setting attributes failed, status = %p", status);
+ debug_printf ("Setting attributes failed, status = %y", status);
res = 0;
}
else
@@ -1793,13 +1902,13 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
status = NtSetInformationFile (fh, &io, &fdi, sizeof fdi,
FileDispositionInformation);
if (!NT_SUCCESS (status))
- debug_printf ("Setting delete dispostion failed, status = %p", status);
+ debug_printf ("Setting delete dispostion failed, status = %y", status);
}
NtClose (fh);
done:
- syscall_printf ("%d = symlink_worker(%s, %s, %d, %d)", res, oldpath,
- newpath, mk_winsym, isdevice);
+ syscall_printf ("%d = symlink_worker(%s, %s, %d)",
+ res, oldpath, newpath, isdevice);
if (has_trailing_dirsep)
free ((void *) newpath);
return res;
@@ -1838,7 +1947,7 @@ symlink_info::check_shortcut (HANDLE h)
set_error (EIO);
return 0;
}
- if (fsi.EndOfFile.QuadPart <= sizeof (win_shortcut_hdr)
+ if (fsi.EndOfFile.QuadPart <= (LONGLONG) sizeof (win_shortcut_hdr)
|| fsi.EndOfFile.QuadPart > 4 * 65536)
return 0;
if (fsi.EndOfFile.LowPart < NT_MAX_PATH * sizeof (WCHAR))
@@ -1913,7 +2022,7 @@ symlink_info::check_sysfile (HANDLE h)
sizeof (cookie_buf), &off, NULL);
if (!NT_SUCCESS (status))
{
- debug_printf ("ReadFile1 failed %p", status);
+ debug_printf ("ReadFile1 failed %y", status);
if (status != STATUS_END_OF_FILE)
set_error (EIO);
return 0;
@@ -2000,7 +2109,7 @@ symlink_info::check_reparse_point (HANDLE h, bool remote)
}
if (!NT_SUCCESS (status))
{
- debug_printf ("NtFsControlFile(FSCTL_GET_REPARSE_POINT) failed, %p",
+ debug_printf ("NtFsControlFile(FSCTL_GET_REPARSE_POINT) failed, %y",
status);
set_error (EIO);
return 0;
@@ -2412,7 +2521,7 @@ restart:
FILE_OPEN_REPARSE_POINT
| FILE_OPEN_FOR_BACKUP_INTENT,
eabuf, easize);
- debug_printf ("%p = NtCreateFile (%S)", status, &upath);
+ debug_printf ("%y = NtCreateFile (%S)", status, &upath);
/* No right to access EAs or EAs not supported? */
if (!NT_SUCCESS (status)
&& (status == STATUS_ACCESS_DENIED
@@ -2435,7 +2544,7 @@ restart:
&attr, &io, FILE_SHARE_VALID_FLAGS,
FILE_OPEN_REPARSE_POINT
| FILE_OPEN_FOR_BACKUP_INTENT);
- debug_printf ("%p = NtOpenFile (no-EAs %S)", status, &upath);
+ debug_printf ("%y = NtOpenFile (no-EAs %S)", status, &upath);
}
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
{
@@ -2451,7 +2560,7 @@ restart:
&attr, &io, FILE_SHARE_VALID_FLAGS,
FILE_OPEN_REPARSE_POINT
| FILE_OPEN_FOR_BACKUP_INTENT);
- debug_printf ("%p = NtOpenFile (broken-UDF, %S)", status, &upath);
+ debug_printf ("%y = NtOpenFile (broken-UDF, %S)", status, &upath);
attr.Attributes = 0;
if (NT_SUCCESS (status))
{
@@ -2504,6 +2613,22 @@ restart:
}
}
}
+ else if (status == STATUS_NETWORK_OPEN_RESTRICTION
+ || status == STATUS_SYMLINK_CLASS_DISABLED)
+ {
+ /* These status codes are returned if you try to open a native
+ symlink and the usage of this kind of symlink is forbidden
+ (see fsutil). Since we can't open them at all, not even for
+ stat purposes, we have to return a POSIX error code which is
+ at least a bit helpful.
+
+ Additionally Windows 8 introduces a bug in NFS: If you have
+ a symlink to a directory, with symlinks underneath, resolving
+ the second level of symlinks fails if remote->remote symlinks
+ are disabled in fsutil. Unfortunately that's the default. */
+ set_error (ELOOP);
+ break;
+ }
if (NT_SUCCESS (status)
/* Check file system while we're having the file open anyway.
@@ -2526,7 +2651,7 @@ restart:
}
if (!NT_SUCCESS (status))
{
- debug_printf ("%p = NtQueryInformationFile (%S)", status, &upath);
+ debug_printf ("%y = NtQueryInformationFile (%S)", status, &upath);
fileattr = INVALID_FILE_ATTRIBUTES;
/* One of the inner path components is invalid, or the path contains
@@ -2559,7 +2684,7 @@ restart:
OBJECT_ATTRIBUTES dattr;
HANDLE dir;
struct {
- FILE_BOTH_DIRECTORY_INFORMATION fdi;
+ FILE_BOTH_DIR_INFORMATION fdi;
WCHAR dummy_buf[NAME_MAX + 1];
} fdi_buf;
@@ -2573,7 +2698,7 @@ restart:
| FILE_DIRECTORY_FILE);
if (!NT_SUCCESS (status))
{
- debug_printf ("%p = NtOpenFile(%S)", status, &dirname);
+ debug_printf ("%y = NtOpenFile(%S)", status, &dirname);
/* There's a special case if the file is itself the root
of a drive which is not accessible by the current user.
This case is only recognized by the length of the
@@ -2593,7 +2718,7 @@ restart:
NtClose (dir);
if (!NT_SUCCESS (status))
{
- debug_printf ("%p = NtQueryDirectoryFile(%S)",
+ debug_printf ("%y = NtQueryDirectoryFile(%S)",
status, &dirname);
if (status == STATUS_NO_SUCH_FILE)
{
@@ -2771,7 +2896,7 @@ restart:
NtClose (h);
}
- syscall_printf ("%d = symlink.check(%s, %p) (%p)",
+ syscall_printf ("%d = symlink.check(%s, %p) (%y)",
res, suffix.path, contents, pflags);
return res;
}
@@ -2809,7 +2934,7 @@ readlink (const char *path, char *buf, size_t buflen)
if (pathbuf.error)
{
set_errno (pathbuf.error);
- syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
+ syscall_printf ("-1 = readlink (%s, %p, %lu)", path, buf, buflen);
return -1;
}
@@ -2841,8 +2966,8 @@ readlink (const char *path, char *buf, size_t buflen)
done during the opendir call and the hash or the filename within
the directory. FIXME: Not bullet-proof. */
/* Cygwin internal */
-__ino64_t __stdcall
-hash_path_name (__ino64_t hash, PUNICODE_STRING name)
+ino_t __reg2
+hash_path_name (ino_t hash, PUNICODE_STRING name)
{
if (name->Length == 0)
return hash;
@@ -2855,20 +2980,20 @@ hash_path_name (__ino64_t hash, PUNICODE_STRING name)
return hash;
}
-__ino64_t __stdcall
-hash_path_name (__ino64_t hash, PCWSTR name)
+ino_t __reg2
+hash_path_name (ino_t hash, PCWSTR name)
{
UNICODE_STRING uname;
RtlInitUnicodeString (&uname, name);
return hash_path_name (hash, &uname);
}
-__ino64_t __stdcall
-hash_path_name (__ino64_t hash, const char *name)
+ino_t __reg2
+hash_path_name (ino_t hash, const char *name)
{
UNICODE_STRING uname;
RtlCreateUnicodeStringFromAsciiz (&uname, name);
- __ino64_t ret = hash_path_name (hash, &uname);
+ ino_t ret = hash_path_name (hash, &uname);
RtlFreeUnicodeString (&uname);
return ret;
}
@@ -2899,7 +3024,7 @@ get_current_dir_name (void)
{
const char *pwd = getenv ("PWD");
char *cwd = getcwd (NULL, 0);
- struct __stat64 pwdbuf, cwdbuf;
+ struct stat pwdbuf, cwdbuf;
if (pwd && strcmp (pwd, cwd) != 0
&& stat64 (pwd, &pwdbuf) == 0
@@ -2941,7 +3066,7 @@ chdir (const char *in_dir)
int res = -1;
const char *posix_cwd = NULL;
- int devn = path.get_devn ();
+ dev_t devn = path.get_device ();
if (!path.exists ())
set_errno (ENOENT);
else if (!path.isdir ())
@@ -3177,6 +3302,7 @@ cygwin_create_path (cygwin_conv_path_t what, const void *from)
return to;
}
+#ifndef __x86_64__ /* Disable deprecated functions on x86_64. */
extern "C" int
cygwin_conv_to_win32_path (const char *path, char *win32_path)
@@ -3208,6 +3334,8 @@ cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
MAX_PATH);
}
+#endif /* !__x86_64__ */
+
/* The realpath function is required by POSIX:2008. */
extern "C" char *
@@ -3344,6 +3472,14 @@ conv_path_list_buf_size (const char *path_list, bool to_posix)
return size;
}
+extern "C" ssize_t
+env_PATH_to_posix (const void *win32, void *posix, size_t size)
+{
+ return_with_errno (conv_path_list ((const char *) win32, (char *) posix,
+ size, ENV_CVT));
+}
+
+#ifndef __x86_64__ /* Disable deprecated functions on x86_64. */
extern "C" int
cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
@@ -3357,13 +3493,6 @@ cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
return conv_path_list_buf_size (path_list, false);
}
-extern "C" ssize_t
-env_PATH_to_posix (const void *win32, void *posix, size_t size)
-{
- return_with_errno (conv_path_list ((const char *) win32, (char *) posix,
- size, ENV_CVT));
-}
-
extern "C" int
cygwin_win32_to_posix_path_list (const char *win32, char *posix)
{
@@ -3378,6 +3507,8 @@ cygwin_posix_to_win32_path_list (const char *posix, char *win32)
CCP_POSIX_TO_WIN_A | CCP_RELATIVE));
}
+#endif /* !__x86_64__ */
+
extern "C" ssize_t
cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, void *to,
size_t size)
@@ -3385,7 +3516,6 @@ cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, void *to,
int ret;
char *winp = NULL;
void *orig_to = NULL;
- size_t orig_size = (size_t) -1;
tmp_pathbuf tp;
switch (what & CCP_CONVTYPE_MASK)
@@ -3403,7 +3533,6 @@ cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, void *to,
* sizeof (WCHAR);
what = (what & ~CCP_CONVTYPE_MASK) | CCP_POSIX_TO_WIN_A;
orig_to = to;
- orig_size = size;
to = (void *) tp.w_get ();
size = 65536;
break;
@@ -3685,8 +3814,6 @@ fcwd_access_t::SetVersionFromPointer (PBYTE buf_p, bool is_buffer)
fast_cwd_version () = FCWD_OLD;
}
-#define peek32(x) (*(uint32_t *)(x))
-
/* This function scans the code in ntdll.dll to find the address of the
global variable used to access the CWD starting with Vista. While the
pointer is global, it's not exported from the DLL, unfortunately.
@@ -3696,6 +3823,99 @@ fcwd_access_t::SetVersionFromPointer (PBYTE buf_p, bool is_buffer)
Windows 7 32/64 bit, Server 2008 R2 (which is only 64 bit anyway),
and W8CP 32/64 bit. There's some hope this will still work for
Windows 8 RTM... */
+
+#ifdef __x86_64__
+
+#define peek32(x) (*(int32_t *)(x))
+
+static fcwd_access_t **
+find_fast_cwd_pointer ()
+{
+ /* Fetch entry points of relevant functions in ntdll.dll. */
+ HMODULE ntdll = GetModuleHandle ("ntdll.dll");
+ if (!ntdll)
+ return NULL;
+ const uint8_t *get_dir = (const uint8_t *)
+ GetProcAddress (ntdll, "RtlGetCurrentDirectory_U");
+ const uint8_t *ent_crit = (const uint8_t *)
+ GetProcAddress (ntdll, "RtlEnterCriticalSection");
+ if (!get_dir || !ent_crit)
+ return NULL;
+ /* Search first relative call instruction in RtlGetCurrentDirectory_U. */
+ const uint8_t *rcall = (const uint8_t *) memchr (get_dir, 0xe8, 40);
+ if (!rcall)
+ return NULL;
+ /* Fetch offset from instruction and compute address of called function.
+ This function actually fetches the current FAST_CWD instance and
+ performs some other actions, not important to us. */
+ const uint8_t *use_cwd = rcall + 5 + peek32 (rcall + 1);
+ /* Next we search for the locking mechanism and perform a sanity check.
+ On Pre-Windows 8 we basically look for the RtlEnterCriticalSection call.
+ Windows 8 does not call RtlEnterCriticalSection. The code manipulates
+ the FastPebLock manually, probably because RtlEnterCriticalSection has
+ been converted to an inline function. Either way, we test if the code
+ uses the FastPebLock. */
+ const uint8_t *movrbx;
+ const uint8_t *lock = (const uint8_t *)
+ memmem ((const char *) use_cwd, 80,
+ "\xf0\x0f\xba\x35", 4);
+ if (lock)
+ {
+ /* The lock instruction tweaks the LockCount member, which is not at
+ the start of the PRTL_CRITICAL_SECTION structure. So we have to
+ subtract the offset of LockCount to get the real address. */
+ PRTL_CRITICAL_SECTION lockaddr =
+ (PRTL_CRITICAL_SECTION) (lock + 9 + peek32 (lock + 4)
+ - offsetof (RTL_CRITICAL_SECTION, LockCount));
+ /* Test if lock address is FastPebLock. */
+ if (lockaddr != NtCurrentTeb ()->Peb->FastPebLock)
+ return NULL;
+ /* Search `mov rbx, rel(rip)'. This is the instruction fetching the
+ address of the current fcwd_access_t pointer, and it should be pretty
+ near to the locking stuff. */
+ movrbx = (const uint8_t *) memmem ((const char *) lock, 40,
+ "\x48\x8b\x1d", 3);
+ }
+ else
+ {
+ /* Search lea rcx, rel(rip). This loads the address of the lock into
+ $rcx for the subsequent RtlEnterCriticalSection call. */
+ lock = (const uint8_t *) memmem ((const char *) use_cwd, 80,
+ "\x48\x8d\x0d", 3);
+ if (!lock)
+ return NULL;
+ PRTL_CRITICAL_SECTION lockaddr =
+ (PRTL_CRITICAL_SECTION) (lock + 7 + peek32 (lock + 3));
+ /* Test if lock address is FastPebLock. */
+ if (lockaddr != NtCurrentTeb ()->Peb->FastPebLock)
+ return NULL;
+ /* Next is the call RtlEnterCriticalSection. */
+ lock += 7;
+ if (lock[0] != 0xe8)
+ return NULL;
+ const uint8_t *call_addr = (const uint8_t *)
+ (lock + 5 + peek32 (lock + 1));
+ if (call_addr != ent_crit)
+ return NULL;
+ /* In contrast to the above Windows 8 code, we don't have to search
+ for the `mov rbx, rel(rip)' instruction. It follows right after
+ the call to RtlEnterCriticalSection. */
+ movrbx = lock + 5;
+ }
+ if (!movrbx)
+ return NULL;
+ /* Check that the next instruction tests if the fetched value is NULL. */
+ const uint8_t *testrbx = (const uint8_t *)
+ memmem (movrbx + 7, 3, "\x48\x85\xdb", 3);
+ if (!testrbx)
+ return NULL;
+ /* Compute address of the fcwd_access_t ** pointer. */
+ return (fcwd_access_t **) (testrbx + peek32 (movrbx + 3));
+}
+#else
+
+#define peek32(x) (*(uint32_t *)(x))
+
static fcwd_access_t **
find_fast_cwd_pointer ()
{
@@ -3726,9 +3946,8 @@ find_fast_cwd_pointer ()
const uint8_t *mov_pfast_cwd;
if (movedi[0] == 0x8b && movedi[1] == 0xff) /* mov edi,edi -> W8 */
{
- /* Windows 8 CP 32 bit (after a Windows Update?) does not call
- RtlEnterCriticalSection. For some reason the function manipulates
- the FastPebLock manually, kind of like RtlEnterCriticalSection has
+ /* Windows 8 does not call RtlEnterCriticalSection. The code manipulates
+ the FastPebLock manually, probably because RtlEnterCriticalSection has
been converted to an inline function.
Next we search for a `mov eax, some address'. This address points
@@ -3782,6 +4001,7 @@ find_fast_cwd_pointer ()
return NULL;
return (fcwd_access_t **) peek32 (mov_pfast_cwd + 2);
}
+#endif
static fcwd_access_t **
find_fast_cwd ()
@@ -3906,7 +4126,7 @@ cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count)
RtlSetCurrentDirectory_U (error ? &ro_u_pipedir : &win32);
if (!NT_SUCCESS (status))
{
- debug_printf ("RtlSetCurrentDirectory_U(%S) failed, %p",
+ debug_printf ("RtlSetCurrentDirectory_U(%S) failed, %y",
error ? &ro_u_pipedir : &win32, status);
return;
}
@@ -4276,7 +4496,7 @@ cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
cwd_lock.release ();
out:
- syscall_printf ("(%s) = cwdstuff::get (%p, %d, %d, %d), errno %d",
+ syscall_printf ("(%s) = cwdstuff::get (%p, %u, %d, %d), errno %d",
buf, buf, ulen, need_posix, with_chroot, errno);
MALLOC_CHECK;
return buf;
@@ -4317,7 +4537,7 @@ etc::test_file_change (int n)
{
res = true;
memset (last_modified + n, 0, sizeof (last_modified[n]));
- debug_printf ("NtQueryFullAttributesFile (%S) failed, %p",
+ debug_printf ("NtQueryFullAttributesFile (%S) failed, %y",
fn[n].ObjectName, status);
}
else
@@ -4355,7 +4575,7 @@ etc::dir_changed (int n)
if (!NT_SUCCESS (status))
{
#ifdef DEBUGGING
- system_printf ("NtOpenFile (%S) failed, %p",
+ system_printf ("NtOpenFile (%S) failed, %y",
dir.get_nt_native_path (), status);
#endif
changed_h = INVALID_HANDLE_VALUE;
@@ -4370,7 +4590,7 @@ etc::dir_changed (int n)
if (!NT_SUCCESS (status))
{
#ifdef DEBUGGING
- system_printf ("NtNotifyChangeDirectoryFile (1) failed, %p",
+ system_printf ("NtNotifyChangeDirectoryFile (1) failed, %y",
status);
#endif
NtClose (changed_h);
@@ -4392,7 +4612,7 @@ etc::dir_changed (int n)
if (!NT_SUCCESS (status))
{
#ifdef DEBUGGING
- system_printf ("NtNotifyChangeDirectoryFile (2) failed, %p",
+ system_printf ("NtNotifyChangeDirectoryFile (2) failed, %y",
status);
#endif
NtClose (changed_h);