* Throughout, use __try/__except/__endtry blocks, rather than myfault

handler.
	* cygtls.cc (_cygtls::remove): Accommodate the fact that pathbufs
	has been moved from _local_storage to _cygtls.
	* cygtls.h (class tls_pathbuf): Add comment to hint to gendef usage
	of counters.  Change type of counters to uint32_t for clarity.
	Remove _cygtls as friend class.
	(struct _local_storage): Move pathbufs from here...
	(struct _cygtls): ...to here, allowing to access it from _sigbe.
	(class san): Only define on 32 bit.  Remove errno, _c_cnt and _w_cnt
	members.
	(san::setup): Drop parameter.  Don't initialize removed members.
	(san::leave): Don't set removed members.
	(class myfault): Only define on 32 bit.
	(myfault::faulted): Only keep implementation not taking any parameter.
	Drop argument in call to sebastian.setup.
	(__try/__leave/__except/__endtry): Implement to support real SEH.  For
	now stick to SJLJ on 32 bit.
	* dcrt0.cc (dll_crt0_0): Drop 64 bit call to
	exception::install_myfault_handler.
	* exception.h (exception_handler): Define with EXCEPTION_DISPOSITION
	as return type.
	(PDISPATCHER_CONTEXT): Define as void * on 32 bit.  Define as pointer
	to _DISPATCHER_CONTEXT on 64 bit.
	(class exception): Define separately for 32 and 64 bit.
	(exception::myfault): Add handler for myfault SEH handling on 64 bit.
	(exception::exception): Fix mangled method name to account for change
	in type of last parameter.
	(exception::install_myfault_handler): Remove.
	* exceptions.cc (exception::myfault_handle): Remove.
	(exception::myfault): New SEH handler for 64 bit.
	* gendef (_sigbe): Set tls_pathbuf counters to 0 explicitely when
	returning to the caller.
	* ntdll.h: Move a comment to a better place.
	(struct _SCOPE_TABLE): Define on 64 bit.
	* thread.cc (verifyable_object_isvalid): Remove gcc 4.7 workaround.
	* tls_pbuf.cc (tls_pbuf): Fix to accommodate new place of pathbufs.
	(tls_pathbuf::destroy): Change type of loop variables to uint32_t.
	* tls_pbuf.h (class tmp_pathbuf): Change type of buffer counters to
	uint32_t.  Accommodate new place of pathbufs.
	* tlsoffsets.h: Regenerate.
	* tlsoffsets64.h: Regenerate.
This commit is contained in:
Corinna Vinschen
2014-08-22 09:21:33 +00:00
parent 33ed7bb5bc
commit 3f3bd10104
41 changed files with 6383 additions and 5924 deletions

View File

@@ -60,167 +60,171 @@ read_ea (HANDLE hdl, path_conv &pc, const char *name, char *value, size_t size)
EA in the file is returned twice. */
char lastname[MAX_EA_NAME_LEN];
myfault efault;
if (efault.faulted (EFAULT))
goto out;
pc.get_object_attr (attr, sec_none_nih);
debug_printf ("read_ea (%S, %s, %p, %lu)",
attr.ObjectName, name, value, size);
/* Early open if handle is NULL. This allows to return error codes like
ENOENT before we actually check for the correctness of the EA name and
stuff like that. */
if (!hdl)
__try
{
status = NtOpenFile (&h, READ_CONTROL | FILE_READ_EA, &attr, &io,
FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
goto out;
}
hdl = NULL;
}
pc.get_object_attr (attr, sec_none_nih);
fea = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
debug_printf ("read_ea (%S, %s, %p, %lu)",
attr.ObjectName, name, value, size);
if (name)
{
size_t nlen;
/* For compatibility with Linux, we only allow user xattrs and
return ENOTSUP otherwise. */
if (ascii_strncasematch (name, "user.", 5))
name += 5;
else
/* Early open if handle is NULL. This allows to return error codes like
ENOENT before we actually check for the correctness of the EA name and
stuff like that. */
if (!hdl)
{
set_errno (ENOTSUP);
goto out;
}
if ((nlen = strlen (name)) >= MAX_EA_NAME_LEN)
{
set_errno (EINVAL);
return -1;
}
glen = sizeof (FILE_GET_EA_INFORMATION) + nlen;
gea = (PFILE_GET_EA_INFORMATION) alloca (glen);
gea->NextEntryOffset = 0;
gea->EaNameLength = nlen;
strcpy (gea->EaName, name);
}
while (true)
{
if (h)
{
status = NtQueryEaFile (h, &io, fea, EA_BUFSIZ, TRUE, gea, glen,
NULL, TRUE);
if (status != STATUS_ACCESS_DENIED || !hdl)
break;
}
status = NtOpenFile (&h, READ_CONTROL | FILE_READ_EA, &attr, &io,
FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
break;
hdl = NULL;
}
if (!NT_SUCCESS (status))
{
switch (status)
{
case STATUS_NO_EAS_ON_FILE:
ret = 0;
break;
case STATUS_INVALID_DEVICE_REQUEST:
set_errno (ENOTSUP);
break;
case STATUS_NOT_FOUND:
/* STATUS_NOT_FOUND is returned when calling NtQueryEaFile on NFS.
In theory this should mean that the file just has no EAs, but in
fact NFS doesn't support EAs, other than the EAs which are used
for NFS requests. We're playing safe and convert STATUS_NOT_FOUND
to ENOATTR, unless we're on NFS, where we convert it to ENOTSUP. */
set_errno (pc.fs_is_nfs () ? ENOTSUP : ENOATTR);
break;
case STATUS_NONEXISTENT_EA_ENTRY:
/* Actually STATUS_NONEXISTENT_EA_ENTRY is either never generated, or
it was only generated in some old and long forgotton NT version.
See below. For safty reasons, we handle it here, nevertheless. */
set_errno (ENOATTR);
break;
default:
__seterrno_from_nt_status (status);
break;
}
goto out;
}
if (name)
{
/* Another weird behaviour of NtQueryEaFile. If you ask for a
specific EA which is not present in the file's EA list, you don't
get a useful error code like STATUS_NONEXISTENT_EA_ENTRY. Rather
NtQueryEaFile returns success with the entry's EaValueLength
set to 0. */
if (!fea->EaValueLength)
{
set_errno (ENOATTR);
goto out;
}
if (size > 0)
{
if (size < fea->EaValueLength)
status = NtOpenFile (&h, READ_CONTROL | FILE_READ_EA, &attr, &io,
FILE_SHARE_VALID_FLAGS,
FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
{
set_errno (ERANGE);
goto out;
__seterrno_from_nt_status (status);
__leave;
}
memcpy (value, fea->EaName + fea->EaNameLength + 1,
fea->EaValueLength);
hdl = NULL;
}
ret = fea->EaValueLength;
}
else
{
ret = 0;
do
fea = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
if (name)
{
fea->EaNameLength += 5; /* "user." */
size_t nlen;
/* For compatibility with Linux, we only allow user xattrs and
return ENOTSUP otherwise. */
if (ascii_strncasematch (name, "user.", 5))
name += 5;
else
{
set_errno (ENOTSUP);
__leave;
}
if ((nlen = strlen (name)) >= MAX_EA_NAME_LEN)
{
set_errno (EINVAL);
return -1;
}
glen = sizeof (FILE_GET_EA_INFORMATION) + nlen;
gea = (PFILE_GET_EA_INFORMATION) alloca (glen);
gea->NextEntryOffset = 0;
gea->EaNameLength = nlen;
strcpy (gea->EaName, name);
}
while (true)
{
if (h)
{
status = NtQueryEaFile (h, &io, fea, EA_BUFSIZ, TRUE, gea, glen,
NULL, TRUE);
if (status != STATUS_ACCESS_DENIED || !hdl)
break;
}
status = NtOpenFile (&h, READ_CONTROL | FILE_READ_EA, &attr, &io,
FILE_SHARE_VALID_FLAGS,
FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
break;
hdl = NULL;
}
if (!NT_SUCCESS (status))
{
switch (status)
{
case STATUS_NO_EAS_ON_FILE:
ret = 0;
break;
case STATUS_INVALID_DEVICE_REQUEST:
set_errno (ENOTSUP);
break;
case STATUS_NOT_FOUND:
/* STATUS_NOT_FOUND is returned when calling NtQueryEaFile on NFS.
In theory this should mean that the file just has no EAs, but
in fact NFS doesn't support EAs, other than the EAs which are
used for NFS requests. We're playing safe and convert
STATUS_NOT_FOUND to ENOATTR, unless we're on NFS, where we
convert it to ENOTSUP. */
set_errno (pc.fs_is_nfs () ? ENOTSUP : ENOATTR);
break;
case STATUS_NONEXISTENT_EA_ENTRY:
/* Actually STATUS_NONEXISTENT_EA_ENTRY is either never generated,
or it was only generated in some old and long forgotton NT
version. See below. For safty reasons, we handle it here,
nevertheless. */
set_errno (ENOATTR);
break;
default:
__seterrno_from_nt_status (status);
break;
}
__leave;
}
if (name)
{
/* Another weird behaviour of NtQueryEaFile. If you ask for a
specific EA which is not present in the file's EA list, you don't
get a useful error code like STATUS_NONEXISTENT_EA_ENTRY. Rather
NtQueryEaFile returns success with the entry's EaValueLength
set to 0. */
if (!fea->EaValueLength)
{
set_errno (ENOATTR);
__leave;
}
if (size > 0)
{
if ((size_t) ret + fea->EaNameLength + 1 > size)
if (size < fea->EaValueLength)
{
set_errno (ERANGE);
goto out;
__leave;
}
/* For compatibility with Linux, we always prepend "user." to
the attribute name, so effectively we only support user
attributes from a application point of view. */
char tmpbuf[MAX_EA_NAME_LEN * 2];
char *tp = stpcpy (tmpbuf, "user.");
stpcpy (tp, fea->EaName);
/* NTFS stores all EA names in uppercase unfortunately. To keep
compatibility with ext/xfs EA namespaces and accompanying
tools, which expect the namespaces to be lower case, we return
EA names in lowercase if the file is on a native NTFS. */
if (pc.fs_is_ntfs ())
strlwr (tp);
tp = stpcpy (value, tmpbuf) + 1;
ret += tp - value;
value = tp;
memcpy (value, fea->EaName + fea->EaNameLength + 1,
fea->EaValueLength);
}
else
ret += fea->EaNameLength + 1;
strcpy (lastname, fea->EaName);
status = NtQueryEaFile (h, &io, fea, EA_BUFSIZ, TRUE, NULL, 0,
NULL, FALSE);
ret = fea->EaValueLength;
}
else
{
ret = 0;
do
{
fea->EaNameLength += 5; /* "user." */
if (size > 0)
{
if ((size_t) ret + fea->EaNameLength + 1 > size)
{
set_errno (ERANGE);
__leave;
}
/* For compatibility with Linux, we always prepend "user." to
the attribute name, so effectively we only support user
attributes from a application point of view. */
char tmpbuf[MAX_EA_NAME_LEN * 2];
char *tp = stpcpy (tmpbuf, "user.");
stpcpy (tp, fea->EaName);
/* NTFS stores all EA names in uppercase unfortunately. To
keep compatibility with ext/xfs EA namespaces and
accompanying tools, which expect the namespaces to be
lower case, we return EA names in lowercase if the file
is on a native NTFS. */
if (pc.fs_is_ntfs ())
strlwr (tp);
tp = stpcpy (value, tmpbuf) + 1;
ret += tp - value;
value = tp;
}
else
ret += fea->EaNameLength + 1;
strcpy (lastname, fea->EaName);
status = NtQueryEaFile (h, &io, fea, EA_BUFSIZ, TRUE, NULL, 0,
NULL, FALSE);
}
while (NT_SUCCESS (status) && strcmp (lastname, fea->EaName) != 0);
}
while (NT_SUCCESS (status) && strcmp (lastname, fea->EaName) != 0);
}
out:
__except (EFAULT) {}
__endtry
if (!hdl)
CloseHandle (h);
debug_printf ("%d = read_ea(%S, %s, %p, %lu)",
@@ -241,120 +245,121 @@ write_ea (HANDLE hdl, path_conv &pc, const char *name, const char *value,
ULONG flen;
size_t nlen;
myfault efault;
if (efault.faulted (EFAULT))
goto out;
pc.get_object_attr (attr, sec_none_nih);
debug_printf ("write_ea (%S, %s, %p, %lu, %d)",
attr.ObjectName, name, value, size, flags);
/* Early open if handle is NULL. This allows to return error codes like
ENOENT before we actually check for the correctness of the EA name and
stuff like that. */
if (!hdl)
__try
{
status = NtOpenFile (&h, READ_CONTROL | FILE_WRITE_EA, &attr, &io,
FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
pc.get_object_attr (attr, sec_none_nih);
debug_printf ("write_ea (%S, %s, %p, %lu, %d)",
attr.ObjectName, name, value, size, flags);
/* Early open if handle is NULL. This allows to return error codes like
ENOENT before we actually check for the correctness of the EA name and
stuff like that. */
if (!hdl)
{
__seterrno_from_nt_status (status);
goto out;
status = NtOpenFile (&h, READ_CONTROL | FILE_WRITE_EA, &attr, &io,
FILE_SHARE_VALID_FLAGS,
FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
__leave;
}
hdl = NULL;
}
hdl = NULL;
}
/* For compatibility with Linux, we only allow user xattrs and
return ENOTSUP otherwise. */
if (!ascii_strncasematch (name, "user.", 5))
{
set_errno (ENOTSUP);
goto out;
}
/* For compatibility with Linux, we only allow user xattrs and
return ENOTSUP otherwise. */
if (!ascii_strncasematch (name, "user.", 5))
{
set_errno (ENOTSUP);
__leave;
}
/* removexattr is supposed to fail with ENOATTR if the requested EA is not
available. This is equivalent to the XATTR_REPLACE flag for setxattr. */
if (!value)
flags = XATTR_REPLACE;
/* removexattr is supposed to fail with ENOATTR if the requested EA is
not available. This is equivalent to XATTR_REPLACE for setxattr. */
if (!value)
flags = XATTR_REPLACE;
if (flags)
{
if (flags != XATTR_CREATE && flags != XATTR_REPLACE)
if (flags)
{
if (flags != XATTR_CREATE && flags != XATTR_REPLACE)
{
set_errno (EINVAL);
__leave;
}
ssize_t rret = read_ea (hdl, pc, name, NULL, 0);
if (flags == XATTR_CREATE && rret > 0)
{
set_errno (EEXIST);
__leave;
}
if (flags == XATTR_REPLACE && rret < 0)
__leave;
}
/* Skip "user." prefix. */
name += 5;
if ((nlen = strlen (name)) >= MAX_EA_NAME_LEN)
{
set_errno (EINVAL);
goto out;
__leave;
}
ssize_t rret = read_ea (hdl, pc, name, NULL, 0);
if (flags == XATTR_CREATE && rret > 0)
flen = sizeof (FILE_FULL_EA_INFORMATION) + nlen + 1 + size;
fea = (PFILE_FULL_EA_INFORMATION) alloca (flen);
fea->NextEntryOffset = 0;
fea->Flags = 0;
fea->EaNameLength = nlen;
fea->EaValueLength = size;
strcpy (fea->EaName, name);
if (value)
memcpy (fea->EaName + fea->EaNameLength + 1, value, size);
while (true)
{
set_errno (EEXIST);
goto out;
}
if (flags == XATTR_REPLACE && rret < 0)
goto out;
}
/* Skip "user." prefix. */
name += 5;
if ((nlen = strlen (name)) >= MAX_EA_NAME_LEN)
{
set_errno (EINVAL);
goto out;
}
flen = sizeof (FILE_FULL_EA_INFORMATION) + nlen + 1 + size;
fea = (PFILE_FULL_EA_INFORMATION) alloca (flen);
fea->NextEntryOffset = 0;
fea->Flags = 0;
fea->EaNameLength = nlen;
fea->EaValueLength = size;
strcpy (fea->EaName, name);
if (value)
memcpy (fea->EaName + fea->EaNameLength + 1, value, size);
while (true)
{
if (h)
{
status = NtSetEaFile (h, &io, fea, flen);
if (status != STATUS_ACCESS_DENIED || !hdl)
if (h)
{
status = NtSetEaFile (h, &io, fea, flen);
if (status != STATUS_ACCESS_DENIED || !hdl)
break;
}
status = NtOpenFile (&h, READ_CONTROL | FILE_WRITE_EA, &attr, &io,
FILE_SHARE_VALID_FLAGS,
FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
break;
hdl = NULL;
}
status = NtOpenFile (&h, READ_CONTROL | FILE_WRITE_EA, &attr, &io,
FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS (status))
break;
hdl = NULL;
}
if (!NT_SUCCESS (status))
{
switch (status)
{
case STATUS_EA_TOO_LARGE:
/* STATUS_EA_TOO_LARGE has a matching Win32 error ERROR_EA_TABLE_FULL.
For some unknown reason RtlNtStatusToDosError does not translate
STATUS_EA_TOO_LARGE to ERROR_EA_TABLE_FULL, but instead to
ERROR_EA_LIST_INCONSISTENT. This error code is also returned for
STATUS_EA_LIST_INCONSISTENT, which means the incoming EA list is...
inconsistent. For obvious reasons we translate
ERROR_EA_LIST_INCONSISTENT to EINVAL, so we have to handle
STATUS_EA_TOO_LARGE explicitely here, to get the correct mapping
to ENOSPC. */
set_errno (ENOSPC);
break;
case STATUS_INVALID_DEVICE_REQUEST:
set_errno (ENOTSUP);
break;
default:
__seterrno_from_nt_status (status);
break;
switch (status)
{
case STATUS_EA_TOO_LARGE:
/* STATUS_EA_TOO_LARGE has a matching Win32 error code
ERROR_EA_TABLE_FULL. For some reason RtlNtStatusToDosError
does not translate STATUS_EA_TOO_LARGE to ERROR_EA_TABLE_FULL,
but instead to ERROR_EA_LIST_INCONSISTENT. This error code is
also returned for STATUS_EA_LIST_INCONSISTENT, which means the
incoming EA list is... inconsistent. For obvious reasons we
translate ERROR_EA_LIST_INCONSISTENT to EINVAL, so we have to
handle STATUS_EA_TOO_LARGE explicitely here, to get the correct
mapping to ENOSPC. */
set_errno (ENOSPC);
break;
case STATUS_INVALID_DEVICE_REQUEST:
set_errno (ENOTSUP);
break;
default:
__seterrno_from_nt_status (status);
break;
}
}
else
ret = 0;
}
else
ret = 0;
out:
__except (EFAULT) {}
__endtry
if (!hdl)
CloseHandle (h);
debug_printf ("%d = write_ea(%S, %s, %p, %lu, %d)",